REPORTE TRABAJO 1: SOLUCIÓN DE PROBLEMAS DE OPTIMIZACIÓN CON MÉTODOS HEURÍSTICOS

REDES NEURONALES Y ALGORITMOS BIOINSPIRADOS




Presentado por:

Leonardo Federico Corona Torres
David Escobar Ruiz
Johan Sebastian Robles Rincón
Sebastián Soto Arcila



Profesor: Juan David Ospina Arango

Monitor: Andrés Mauricio Zapata Rincón


University Logo

Universidad Nacional de Colombia
Facultad de Minas
Ingeniería de Sistemas e Informática

09 de julio de 2025

Contenidos

Introducción

El presente trabajo trata algunos de los métodos más relevantes de optimización numérica basada en manipulaciones del gradiente de una función objetivo (función a optimizar) y también algoritmos heurísticos basados en el comportamiento de la naturaleza, como lo son los algoritmos evolutivos. Todos estos métodos pueden llegar a ser útiles en distintos contextos en los que se busca optimizar una función para algún fin, como encontrar la mejor ruta entre ciudades o optimizar una función de pérdida en un contexto de aprendizaje de máquina. Cada método tiene particularidades interesantes que se van a explorar de manera general por medio de una breve implementación y ejecución con dos funciones muy utilizadas para probar algoritmos de optimización: la función de Rosenbrock y la función de Rastrigin.

Metodología

Para implementar y documentar la optimización se emplea R Markdown, combinando código R y texto explicativo. Se utilizan librerías para renderizar gráficos y animaciones, librerías para implementar los métodos heurísticos y librerías para manipular los datos. Para los casos 3D (tres variables) es difícil visualizar directamente la función de 3 dimensiones (espacio de 4 variables), por lo que se mostrarán únicamente los puntos óptimos alcanzados.

Parte 1. Optimización numérica

1.1 Selección e implementación de las funciones de prueba

Para observar el comportamiento de cada uno de los métodos de optimización implementados, se optó por la selección de dos funciones de prueba estándar para evaluar algoritmos de optimización: Función de Rosenbrock y Función de Rastrigin. Debido a su complejidad, ambas funciones son indicadores útiles para comparar la eficacia de optimizadores como los AG.

Previo a la implementación de los algoritmos en el lenguaje R y previo a la recopilación de resultados y la derivación de conclusiones a partir de estos, el equipo decidió realizar una breve investigación general de lo que son las funciones de prueba para problemas de optimización. La investigación se realizó de tal forma que, una vez concluída, se pudieran comprender los conceptos hasta el punto de estar en las capacidades responder las siguientes preguntas implícitamente en una breve sección de este trabajo:

  • ¿Qué es una función de prueba en optimización?

  • ¿Para qué se utiliza una función de prueba en optimización?

  • ¿Cómo se pueden clasificar las funciones de prueba?

  • ¿Cuáles son algunas de las funciones de prueba más utilizadas?

A continuación se presenta dicha sección para luego continuar con el estudio más detallado de las funciones escogidas.

1.1.1 Breve explicación de las funciones de prueba para problemas de optimización

Según (Yang, 2010), una función de prueba es una función con unas propiedades especiales que permite probar si el rendimiento de un método de optimización implementado es aceptable bajo las condiciones especiales que impone la función de prueba. 

Esto es especialmente útil para verificar que el método sea eficiente bajo distintas condiciones en las que se espera que se implemente, como por ejemplo, casos en los que la función tiene múltiples mínimos y/o máximos locales.

Según (Molga, 2005), las funciones de prueba se pueden ubicar en una de las siguientes clases, todas siendo funciones continuas:

  • Clase 1: Unimodal, convexa, multidimensional.
  • Clase 2: Multimodal, dos dimensiones con un número pequeño de extremos locales.
  • Clase 3: Multimodal, dos dimensiones con un gran número de extremos locales.
  • Clase 4: Multimodal, multidimensional, con un número amplio de extremos locales.

En el caso de las funciones elegidas, la función de Rosenbrock se clasificaría como Clase 3 y la de Rastrigin como Clase 2.

Como ejemplo, en la Figura 1 se presentan algunas funciones de prueba que no se eligieron para este trabajo, pero que son igual de relevantes, importantes y comúnmente utilizadas en la práctica (Molga, 2005):

  • Función de De Jong (Clase 1).

  • Función de Griewangk (Clase 2).

  • Función de Langermann (Clase 3).

  • Función de Ackley (Clase 4).

1.1.2 Función de Rosenbrock

Es una función no convexa introducida por Rosenbrock en 1960​ (Wikipedia, s.f., Rosenbrock function). Su paisaje forma un valle curvo estrecho que dificulta la convergencia hacia el mínimo.

Definición en n dimensiones:

\(f(X) = \sum_{i=1}^{n-1}100(X_{i+1}-X_i^2)^2 + (1-X_i)^2\) (1)

Definición en 2D:

\(f(x,y)= 100(y-x^2)^2 + (1-x)^2\) (2)

Definición en 3D:

\(f(x,y,z)=100[(y-x^2)^2+(z-y^2)^2] + (1-x)^2 + (1-y)^2\) (3)

Algunas características y propiedades importantes  son las siguientes:

  • El mínimo global está dado por los puntos que cumplen con \(x_1,...,x_n =1\)

  • El dominio de búsqueda consiste de todo el espacio real, es decir, donde cada punto cumple con \(-\infty \leq X_i \leq \infty, 1 \leq i \leq n\).

  • Conocida también como la función banana de Rosenbrock.

  • Tiene forma de valle, el cual es trivial encontrarlo. Sin embargo, la convergencia al mínimo global es difícil.

Estas son algunas hipótesis y expectativas que se tuvieron para el rendimiento de cada método implementado con esta función:

  • Método de descenso de gradiente:

    • Si se ubica el punto inicial sobre las rectas tangentes con mayor gradiente a la función entonces el método llegará más rápido a un mínimo.
    • Por el contrario, si la recta tangente tiene una gradiente más cercana a cero, el método llegará más lentamente, es decir, requerirá de más iteraciones para llegar al punto mínimo.
  • Método de algoritmos evolutivos:

    • Los criterios para seleccionar los individuos a reproducir va a ser muy importante para el rendimiento del método.
  • Método de optimización de partículas:

    • Este método no va a tener muchas dificultades para encontrar el punto óptimo es la función de Rosenbrock.
    • El criterio para parar las iteraciones no va a cambiar mucho los resultados en este caso.
  • Método de evolución diferencial:

    • Se comporta similar a los métodos evolutivos en 2 dimensiones.

La implementación de la función de Rosenbrock en 2, 3 y N dimensiones se muestra a continuación:

# 2 Dimensiones
f_rosenbrock_2d <- function(x, y) {   
  f_value <- 100*(y-(x^2))^2 + ((1-x)^2)   
  return(f_value) 
}  

# 3 Dimensiones
f_rosenbrock_3d <- function(x, y, z) {   
  f_value <- 100*((y-x^2)^2 + (z-y^2)^2) + (1-x)^2 + (1-y)^2   
  return(f_value) 
}

# N Dimensiones
f_rosenbrock <- function(x){
  x_1 <- tail(x, -1)
  x <- head(x, -1)
  z <- sum((100*((x_1-(x^2))^2))+((1-x)^2))
  return(z)
}

Las gráficas de la función de Rosenbrock en 2 y 3 dimensiones se muestran a continuación:

Gráfica de la función de Rosenbrock 2D

Gráfica de la función de Rosenbrock 2D

Gráfica de la función de Rosenbrock 3D

Gráfica de la función de Rosenbrock 3D

1.1.3 Función de Rastrigin

La función Rastrigin (1974) es una función no convexa y altamente multimodal, con numerosos mínimos locales, lo que la hace difícil de optimizar​ (Wikipedia, s.f., Rastrigin function).

Presenta múltiples mínimos locales dispuestos de forma regular​, lo que lo convierte en un desafío típico para algoritmos de optimización.

Definición en n dimensiones:

\(f(X)=An + \sum_{i=1}^n[X_i^2 -A\cos(2\pi X_i)], A=10\) (4)

Definición en 2D:

\(f(x,y)=x^2+y^2+A[2-\cos(2\pi x) - \cos(2\pi y)], A=10\) (5)

Definición en 3D:

\(f(x,y)=x^2+y^2+z^2+A[3-\cos(2\pi x) - \cos(2\pi y)-\cos(2\pi z)], A=10\) (6)

Algunas características y propiedades importantes son las siguientes:

  • El mínimo global se alcanza cuando el vector es un vector nulo, es decir, \(X=[0,...,0]\) para n dimensiones.

  • El dominio de búsqueda cumple con \(-5.12 \leq X_i \leq 5.12\).

  • Particularmente, hallar el mínimo de esta función es un problema difícil debido a la larga cantidad de mínimos locales.

Estas son algunas hipótesis y expectativas que se tuvieron para el rendimiento de cada método implementado con esta función:

  • Método de descenso de gradiente:

    • El éxito del método en alcanzar un mínimo dependerá enormemente del punto inicial elegido debido a los múltiples mínimos locales que tiene esta función.
  • Método de algoritmos evolutivos:

    • Es importante hacer una buena representación de los individuos, ya que el rendimiento puede variar dependiendo de la selección.
    • La población inicial debe ser representativa, diferentes entre ellos y que no sean demasiados. Para esta función en particular encontrar la solución óptima va a depender mucho de la probabilidad de mutación
  • Método de optimización de partículas:

    • La ubicación de la nube de partículas va a afectar el rendimiento en esta función, ya que el algoritmo puede quedarse estancado en un mínimo local si la ubicación no es la mejor.
    • El criterio para detener el algoritmo debe estar bien ajustado, para evitar estancamientos.
  • Método de evolución diferencial:

    • Es más eficiente que los otros métodos evolutivos ya que su fuerte son las múltiples dimensiones.

La implementación de la función de Rastrigin en 2, 3 y N dimensiones se muestra a continuación:

# 2 Dimensiones 
f_rastrigin_2d <- function(x, y) {
  A = 10   
  f_value <- x^2 + y^2 + A*(2 - cos(2*pi*x) - cos(2*pi*y))   
  return(f_value) 
}  

# 3 Dimensiones 
f_rastrigin_3d <- function(x, y, z) {   
  A = 10   
  f_value <- x^2 + y^2 + z^2 + A*(3 - cos(2*pi*x) - cos(2*pi*y) - cos(2*pi*z))   
  return(f_value) 
}

# N Dimensiones
f_rastrigin <-function(x){
  A <- 10
  n <- length(x)
  z <- (A*n) + sum(x^2 - A*cos(2*pi*x))
  return(z)
}

Las gráficas de la función de Rastrigin en 2 y 3 dimensiones se muestran a continuación:

Gráfica de la función de Rastrigin 2D

Gráfica de la función de Rastrigin 2D

Gráfica de la función de Rastrigin 3D

Gráficas de la función de Rastrigin 3D

1.2 Método de descenso de gradiente

El método de optimización por descenso de gradiente es una técnica iterativa utilizada para encontrar el mínimo de una función. Consiste en actualizar sucesivamente los valores de las variables en la dirección opuesta al gradiente de la función, con el objetivo de reducir su valor en cada paso.

En nuestro caso, se utilizaron las siguientes variables para implementar el método: X₀, que representa la condición inicial del algoritmo; H, que define el tamaño de la ventana para el cálculo de la derivada numérica; y ETA, que corresponde a la tasa de aprendizaje, es decir, el tamaño del paso que se da en cada iteración hacia el mínimo.

1.2.1 Implementación en R de descenso de gradiente

# Implementación completa de optimizador multivariado por descenso de gradiente
optimizador_mult_numdev <- function(x0,fun,max_eval=100,h=0.01,eta=0.01){
  x <- matrix(NA,ncol =length(x0), nrow = max_eval)
  x[1,] <- x0
  for (i in 2:max_eval){
    num_grad_fun <- num_grad(x[i-1,],fun,h)
    H <- matriz_hessiana(x[i-1,],fun,h)
    cambio <- - eta*solve(H)%*%num_grad_fun
    x[i,] <- x[i-1,] + cambio
    cambio_opt <- sqrt(sum((x[i-1,]-x[i,])^2))
    if (cambio_opt<0.00001){
      break
    }
  }
  return(x[1:i,])
}

1.2.2 Optimización de la función de Rosenbrock en 2 dimensiones

sol_rosen2d <- optimizador_mult_numdev(f_rosenbrock, x0=c(-4,-4), h=0.005, eta=0.5)

La siguiente animación muestra el desempeño de la optimización a traves de su trayectoria:

Animación de la optimización de Rosenbrock 2D

Animación de la optimización de Rosenbrock 2D

1.2.3 Optimización de la función de Rosenbrock en 3 dimensiones

sol_rosen3d <- optimizador_mult_numdev(f_rosenbrock, x0=c(-4,-4,-4), h=0.005, eta=0.5)

En la siguiente tabla de muestran el comportamiento cada 10 iteraciones:

show_table("./Parte 1/Descenso de gradiente/rosenbrock_iter_grad.csv")

Iteracion

<int>

X1

<dbl>

X2

<dbl>

X3

<dbl>

f_x

<dbl>

10 10 -0.4746588 -0.958089003 0.551655990 1.594659e+02
20 20 0.1573142 0.008101639 -0.002158858 1.722186e+00
30 30 0.8622383 0.739978128 0.539436307 9.441027e-02
40 40 0.9951835 0.990348334 0.980616739 1.195241e-04
50 50 0.9970042 0.994027256 0.988090002 4.465851e-05

Tabla 1. Tabla de ejecución de optimización de Rosenbrock 3D utilizando Descenso de Gradiente

1.2.4 Optimización de la función de Rastrigin en 2 dimensiones

sol_ras2d <- optimizador_mult_numdev(f_rastrigin, x0=c(4.5,4.5), h=0.005, eta=2)

La siguiente animación muestra el desempeño de la optimización a traves de su trayectoria:

Animación de la optimización de Rastrigin 2D

Animación de la optimización de Rastrigin 2D

1.2.5 Optimización de la función de Rastrigin en 3 dimensiones

sol_ras3d <- optimizador_mult_numdev(f_rastrigin, x0=c(-4,-4,-4),  h=0.005, eta=2)

En la siguiente tabla de muestran el comportamiento cada 10 iteraciones:

show_table("./Parte 1/Descenso de gradiente/rastrigin_iter_grad.csv")

Iteracion

<int>

X1

<dbl>

X2

<dbl>

X3

<dbl>

f_x

<dbl>

10 10 -3.957646 -3.957646 -3.957646 48.04492
20 20 -3.954028 -3.954028 -3.954028 48.14587
30 30 -3.947836 -3.947836 -3.947836 48.35321
40 40 -3.933194 -3.933194 -3.933194 49.01439
50 50 -3.399662 -3.399662 -3.399662 88.90609
60 60 -4.984220 -4.984220 -4.984971 74.67761
70 70 -4.984487 -4.984487 -4.985301 74.68100
80 80 -4.984775 -4.984775 -4.985663 74.68479
90 90 -4.985087 -4.985087 -4.986062 74.68906
100 100 -4.985429 -4.985429 -4.986505 74.69392

Tabla 2. Tabla de ejecución de optimización de Rastrigin 3D utilizando Descenso de Gradiente

1.2.6 Conclusiones método de desenso del gradiente

El método de optimización por descenso de gradiente se caracteriza por su simplicidad y facilidad de implementación, lo que lo convierte en una herramienta útil para funciones con superficies suaves y relativamente simples. Sin embargo, al aplicarse a funciones altamente no convexas como la función de Rastrigin, este método presenta limitaciones significativas, ya que tiende a quedar atrapado en mínimos locales, dificultando la convergencia hacia una solución global óptima.

1.3 Método de evolución diferencial

La evolución diferencial es un algoritmo de optimización inspirado en la evolución biológica. Funciona manteniendo una población de soluciones, y mejorándolas generación tras generación mediante operaciones de mutación, recombinación y selección.

  • Mutación: se combinan 3 individuos distintos de la población para crear una variante.
  • Recombinación: se mezcla esa variante con el individuo actual.
  • Selección: se escoge el mejor entre el original y el nuevo.

Este proceso se repite varias veces hasta encontrar una solución óptima.

Las variables son: dim, que representa la cantidad de dimensiones o variables del problema; NP, que indica el tamaño de la población o número de soluciones en cada generación; F, que es el factor de mutación y determina la intensidad de la perturbación aplicada a las soluciones; CR, que corresponde a la tasa de recombinación y controla la probabilidad de intercambio de componentes entre vectores; gens, que define el número total de generaciones o iteraciones del algoritmo; y bounds, que establece los límites inferior y superior del espacio de búsqueda para cada dimensión.

1.3.1 Implementación en R de evolución diferencial

evolucion_diferencial <- function(fun_obj, dim = 2, NP = 30, F = 0.8, CR = 0.9,
                                  gens = 100, bounds = c(-5, 5)) {

  # Inicializar población
  poblacion <- matrix(runif(NP * dim, bounds[1], bounds[2]), ncol = dim)
  fitness <- apply(poblacion, 1, fun_obj)

  historial <- numeric(gens)
  mejores <- matrix(NA, gens, dim)

  for (gen in 1:gens) {
    for (i in 1:NP) {
      # Seleccionar 3 índices distintos
      indices <- sample(setdiff(1:NP, i), 3)
      x1 <- poblacion[indices[1], ]
      x2 <- poblacion[indices[2], ]
      x3 <- poblacion[indices[3], ]

      # Mutación
      mutado <- x1 + F * (x2 - x3)

      # Recombinar
      trial <- poblacion[i, ]
      jrand <- sample(1:dim, 1)
      for (j in 1:dim) {
        if (runif(1) < CR || j == jrand) {
          trial[j] <- mutado[j]
        }
      }

      # Selección
      if (fun_obj(trial) < fitness[i]) {
        poblacion[i, ] <- trial
        fitness[i] <- fun_obj(trial)
      }
    }

    # Guardar mejor resultado
    best_idx <- which.min(fitness)
    historial[gen] <- fitness[best_idx]
    mejores[gen, ] <- poblacion[best_idx, ]
  }

  list(mejor = poblacion[which.min(fitness), ],
       valor = min(fitness),
       historial = historial,
       trayectoria = mejores)
}

1.3.2 Optimización de la función de Rosenbrock en 2 dimensiones

En este gráfico se muestran las curvas de nivel de la función de Rosenbrock en dos dimensiones. Estas curvas representan líneas donde la función tiene igual valor, y el valle curvado al centro es donde está el mínimo global (en el punto (1,1)(1,1)).

La línea roja representa la trayectoria que siguió el algoritmo de evolución diferencial durante las iteraciones. Se puede observar cómo el enjambre de soluciones se fue acercando progresivamente hacia el mínimo, mejorando su posición en cada generación.

Animación de la optimización de Rosenbrock 2D

Animación de la optimización de Rosenbrock 2D

El resultado final obtenido fue: [1] 1.000000 1.000001 Valor mínimo encontrado: 1.91e-12

1.3.3 Optimización de la función de Rosenbrock en 3 dimensiones

En esta parte del informe se muestran los resultados numéricos para la optimización de las funciones en 3D. Dado que no se puede visualizar fácilmente en una gráfica 3D de trayectoria, se reportan las mejores posiciones y valores obtenido.

show_table("./Parte 1/Evolucion_Diferencial/rosenbrock_iter_evd.csv")

Iteracion

<int>

X1

<dbl>

X2

<dbl>

X3

<dbl>

f_x

<dbl>

10 10 -0.5851768 0.1130689 0.8649437 8.117769e+01
20 20 0.8804582 0.5209831 0.4780407 1.097578e+01
30 30 0.6909606 0.4626611 0.3574320 2.461728e+00
40 40 0.8538862 0.6791208 0.3539351 1.525006e+00
50 50 0.6618927 0.4963945 0.2269164 7.457276e-01
60 60 0.8752932 0.7583245 0.5976751 1.312261e-01
70 70 0.9673312 0.9327385 0.8779734 1.284198e-02
80 80 1.0023756 1.0066111 1.0136724 4.096946e-04
90 90 1.0023756 1.0066111 1.0136724 4.096946e-04
100 100 0.9998260 0.9998014 0.9996265 2.357928e-06

Tabla 3. Tabla de ejecución de optimización de Rosenbrock 3D utilizando Evolución Diferencial

1.3.4 Optimización de la función de Rastrigin en 2 dimensiones

Aquí se grafican las curvas de nivel de la función de Rastrigin, que es multimodal, es decir, tiene muchos mínimos locales (patrón ondulado). La búsqueda es mucho más compleja que en Rosenbrock.

La línea azul muestra cómo la evolución diferencial se mueve por el espacio de búsqueda y logra escapar de los mínimos locales hasta acercarse al óptimo global, que se encuentra en (0,0)(0,0).

Animación de la optimización de Rastrigin 2D

Animación de la optimización de Rastrigin 2D

Resultado obtenido: [1] 2.176697e-06 -2.015785e-07 Valor mínimo: 9.48e-10

1.3.5 Optimización de la función de Rastrigin en 3 dimensiones

En este caso, el algoritmo encontró una solución cercana al mínimo global, aunque no exacta. Esto es esperable, ya que Rastrigin es mucho más difícil en 3D debido a la gran cantidad de mínimos locales.

show_table("./Parte 1/Evolucion_Diferencial/rastrigin_iter_evd.csv")

Iteracion

<int>

X1

<dbl>

X2

<dbl>

X3

<dbl>

f_x

<dbl>

10 10 1.064334561 1.037971464 -0.086056745 4.73335450
20 20 1.057313204 1.012050066 0.021733277 2.90578529
30 30 1.057313204 1.012050066 0.021733277 2.90578529
40 40 0.036246808 1.031428503 1.009576812 2.55506463
50 50 -1.004720490 -0.025677269 0.022997883 1.24913224
60 60 0.988499542 -0.008651518 0.010258072 1.03894216
70 70 0.988499542 -0.008651518 0.010258072 1.03894216
80 80 -0.025075277 0.041071447 0.020016885 0.53668971
90 90 0.010524114 0.009941041 0.006215324 0.04922793
100 100 -0.004061259 -0.007504267 0.001244800 0.01474968

Tabla 4. Tabla de ejecución de optimización de Rastrigin 3D utilizando Evolución Diferencial

1.3.6 Conclusiones método de evolución diferencial

El algoritmo logró encontrar soluciones muy cercanas al mínimo global en las funciones de Rosenbrock y Rastrigin, tanto en 2D como en 3D.

En la función de Rosenbrock, se observó una convergencia estable y precisa, especialmente en dos dimensiones.

En la función de Rastrigin, que presenta muchos mínimos locales, el método evitó caer en estos y alcanzó buenos resultados.

El rendimiento se mantuvo sólido en tres dimensiones, aunque con una ligera pérdida de precisión en Rastrigin 3D debido a su complejidad.

Fue más robusto que el descenso por gradiente en funciones multimodales, ya que no necesita derivadas ni depende del punto inicial.

La evolución diferencial demostró ser un método confiable y efectivo para resolver problemas de optimización continua.

1.4 Método de optimización de partículas

El método de optimización por enjambre de partículas (PSO, por sus siglas en inglés) es un algoritmo inspirado en el comportamiento colectivo de animales como bandadas de aves o bancos de peces. Funciona mediante un conjunto de partículas (soluciones potenciales) que exploran el espacio de búsqueda moviéndose en función de su propia experiencia y la de sus vecinas. Cada partícula ajusta su posición y velocidad iterativamente para acercarse a la mejor solución conocida, guiada por su mejor posición histórica y la mejor posición global encontrada por el enjambre. Con el tiempo, las partículas tienden a converger hacia una solución óptima o cercana al óptimo.

1.4.1 Implementación en R de optimización de partículas

Se utiliza el paquete pos para implementar el método de la optimización de partículas. Adicionalmente, se implementa una función adicional para crear las animaciones del método de optimización.

1.4.2 Optimización de la función de Rosenbrock en 2 dimensiones

Animación de la optimización de Rosenbrock 2D con PSO

Animación de la optimización de Rosenbrock 2D con PSO

1.4.3 Optimización de la función de Rosenbrock en 3 dimensiones

show_table("./Parte 1/Enjambre de partículas/rosenbrock_iter_pso.csv")

iteracion

<int>

mejor_valor_enjambre

<dbl>

mejor_posicion_enjambre

<chr>

diferencia_abs

<dbl>

10 10 331.7666 -9.51355277365643, 9.55627294905859, 9.52381833492284 1.466955e-01
20 20 331.7941 -9.54545504914603, 9.58341360681124, 9.52306164187284 2.136272e-01
30 30 332.0698 -9.53590113241727, 9.54041577588653, 9.56011765629112 4.444692e-01
40 40 331.7437 -9.52423268435948, 9.52725725394154, 9.5811887290536 3.001570e-01
50 50 331.8203 -9.5142541282931, 9.52908789764021, 9.54155305396948 1.560163e-01
60 60 332.0383 -9.57209212541967, 9.54481467451097, 9.54675150787573 8.420885e-02
70 70 332.1110 -9.54430273204136, 9.53782738376895, 9.54921607427319 1.458293e-02
80 80 332.1347 -9.54429172045766, 9.54774735662854, 9.54976723459583 1.992581e-04
90 90 332.1375 -9.54743114478767, 9.55201686251299, 9.54880483650736 3.227996e-03
100 100 332.1393 -9.55020210478277, 9.54848826976327, 9.54919167244683 2.639027e

Tabla 5. Tabla de ejecución de optimización de Rosenbrock 3D utilizando Optimización de Partículas

1.4.4 Optimización de la función de Rastrigin en 2 dimensiones

Animación de la optimización de Rastrigin 2D con PSO

Animación de la optimización de Rastrigin 2D con PSO

1.4.5 Optimización de la función de Rastrigin en 3 dimensiones

# Parámetros a utilizar
n <- 3
lower_bounds <- -5
upped_bounds <- 5
# Ejecución del método
o_pso <- particle_swarm_optimization(n,f_rastrigin,lower_bounds,upper_bounds)
show_table("./Parte 1/Enjambre de partículas/rastrigin_iter_pso.csv")

iteracion

<int>

mejor_valor_enjambre

<dbl>

mejor_posicion_enjambre

<chr>

diferencia_abs

<dbl>

10 332.1333 9.55062500864904, 9.54736155842502, 9.55448763975004 1.325873e+00
20 331.5406 9.52357446958727, 9.56685821317542, 9.50250205784094 4.792065e-01
30 331.5791 9.56526091259586, 9.600114687037, 9.56518504530152 2.707836e-01
40 331.9865 9.57682593047023, 9.5526306447749, 9.54163679429817 1.399468e-01
50 331.9818 9.5228388940773, 9.54025472242996, 9.5413775386611 3.082020e-01
60 332.0952 9.56461187832995, 9.54815999520477, 9.54883681982856 1.753033e-02
70 332.1266 9.55580067863994, 9.552365632497, 9.54528606283767 5.561529e-03
80 332.1387 9.54750362349369, 9.5488424083441, 9.55047112210335 3.497472e-04
90 332.1391 9.54792760233839, 9.54882584945718, 9.54820282423739 1.332779e-04
100 332.1393 9.54833176359814, 9.54891927922634, 9.54828740925572 1.924380e-05

Tabla 6. Tabla de ejecución de optimización de Rastrigin 3D utilizando Optimización de Partículas

1.4.6 Conclusiones método de optimización de partículas

En el caso de la optimización maximizando las funciones, llegan muy rápido a una solución óptima (dentro de 10 iteraciones). Por otro lado, la optimización minimizando las funciones tardaba un poco más en llegar al óptimo, pero se acercaba mucho al mínimo global.

Estos resultados pueden deberse a la distribución de las partículas por el espacio de búsqueda, permitiendo una optimización más “abierta” a comparación con el método de descenso de gradiente.

1.5 Método de algoritmos evolutivos

Los algoritmos genéticos (AG) son técnicas de búsqueda heurística basadas en procesos de evolución natural​ . En un AG típico se define una función FITNESS que evalúa la calidad de cada solución candidata (individuo). A partir de una población inicial aleatoria, se iteran ciclos donde se seleccionan individuos más aptos, se combinan sus “genes” mediante cruces (crossover) y se introducen modificaciones aleatorias (mutaciones). Estos operadores evolucionan la población hacia regiones con mejor fitness.

Según (Scrucca, 2013), los GAs han sido exitosos en optimizar funciones continuas (diferenciables o no) y discretas. Entre los operadores genéticos clave se destacan:

  • Selección: elige individuos con mayor fitness para reproducirse, imitando la supervivencia del más apto.

  • Cruce (crossover): combina partes de dos soluciones parentales para generar descendencia, explorando nuevas regiones del espacio de búsqueda.

  • Mutación: altera aleatoriamente parte de un individuo (por ejemplo, cambiando un valor de su vector de variables) para introducir diversidad genética y evitar estancamiento en óptimos locales.

Los algoritmos genéticos (AG) son metaheurísticas inspiradas en procesos evolutivos biológicos, que han demostrado eficacia en la búsqueda global de óptimos en funciones complejas​jstatsoft.org Los AG simulan la selección natural, la recombinación (cruce) y la mutación para iterativamente mejorar un conjunto de soluciones candidatas (población). Estas técnicas estocásticas son adecuadas para funciones no lineales, discontinuas o con múltiples óptimos locales donde los métodos basados en derivadas pueden fallar. Para evaluar la robustez de los GA, se realizarán múltiples ejecuciones independientes y se analizará la dispersión del fitness resultante.

Adicionalmente, se definen algunas funciones para poder mostrar por medio de una animación el proceso de optimización para las funciones de Rosenbrock y de Rastrigin.

Analizaremos cada función en 2 y 3 dimensiones, graficando su paisaje antes de la optimización y luego aplicando un AG con múltiples corridas para evaluar la robustez de los resultados.

1.5.1 Implementación en R de algoritmos evolutivos

Se utiliza la función ga() del paquete GA. Para problemas de minimización se define la función de fitness como el negativo del valor objetivo, ya que ga() maximiza por defecto. Se especifican los límites de búsqueda.

Los resúmenes en cada ejecución reportan el mejor fitness encontrado (negativo) y la solución óptima en cada ejecución.

1.5.2 Optimización de la función de Rastrigin en 2 dimensiones

Animación de optimización de Rastrigin 2D con Algoritmo Genético

Animación de la optimización de Rastrigin 2D con Algoritmo Genético

1.5.3 Optimización de la función de Rastrigin en 3 dimensiones

show_table("./Parte 1/Algoritmos_Evolutivos/rastrigin_iter_ae.csv")

Iteration

<int>

Mean

<dbl>

Best

<dbl>

10 -27.23858 -9.049369
20 -25.13381 -9.049369
30 -18.80389 -9.009854
40 -15.61091 -9.009854
50 -10.47414 -9.009854
60 -16.55153 -9.009854
70 -17.38540 -9.007921
80 -10.28919 -9.000909
90 -16.75012 -9.000504
100 -12.30302 -9.000344

Tabla 7. Tabla de ejecución de optimización de Rastrigin 3D utilizando Algoritmos Evolutivos

1.5.4 Optimización de la función de Rosenbrock en 2 dimensiones

Figura 12. Animación de optimización de Rastrigin 2D con Algoritmo Genético.
Figura 12. Animación de optimización de Rastrigin 2D con Algoritmo Genético.

Animación de la optimización de Rosenbrock 2D con Algoritmo Genético

1.5.5 Optimización de la función de Rosenbrock en 3 dimensiones

show_table("./Parte 1/Algoritmos_Evolutivos/rosenbrock_iter_ae.csv")

Iteration

<int>

Mean

<dbl>

Best

<dbl>

10 -1986.9605 -31.398720
20 -456.4471 -31.398720
30 -1656.6944 -31.398720
40 -781.0234 -22.941130
50 -316.4045 -15.920770
60 -721.8341 -14.043030
70 -941.6848 -5.756500
80 -1501.3154 -4.130807
90 -396.4700 -1.327077
100 -1138.0842 -1.327077

Tabla 8. Tabla de ejecución de optimización de Rosenbrock 3D utilizando Algoritmos Evolutivos

1.5.6 Cálculo de estadísticas y análisis

Para evaluar la variabilidad del método estocástico, se repite cada caso al menos 30 veces con semillas distintas. Se registra el mejor valor de fitness (valorizado positivamente) obtenido en cada corrida. Se calcularán estadísticas (media y desviación estándar) del mejor valor de fitness obtenido en 30 ejecuciones independientes de cada caso y se resumirán en una tabla.

Con los vectores de mejores valores (best_vals_ros, etc.), se calculan la media y desviación estándar de cada conjunto de 30 resultados. Por ejemplo, mean_ros y sd_ros arriba y las demas, Para asi presentar los resultados.

Los resultados de las múltiples ejecuciones se resumen en la Tabla 1. Esta tabla muestra la media y desviación estándar del mejor valor de fitness (recordado que es el valor de la función objetivo en su mínimo global, típicamente cercano a 0) para cada combinación de función y dimensión. Se observa que para Rosenbrock 2D, la media del fitness mínimo es cercana a 0 con baja dispersión, reflejando que el GA normalmente encuentra el mínimo global (0) o cercano. Para Rastrigin 2D, la media también puede acercarse a 0, pero con mayor desviación estándar debido a los múltiples mínimos locales. En 3D ambos problemas suelen mostrar valores medios mayores (más alejados de 0) y mayor variabilidad, lo cual indica una mayor dificultad de búsqueda al aumentar la dimensionalidad.

Función Dimensión Media SD
Rosenbrock 2D 0.0285904 0.0460372
Rastrigin 2D 0.0001494 0.0004027
Rosenbrock 3D 3.3777375 2.8046450
Rastrigin 3D 9.0002470 0.0009913

Tabla 9. Estadísticas (media y desviación estándar) del fitness mínimo alcanzado en 30 corridas independientes para cada función y dimensión.

1.5.7 Conclusiones método de algoritmos evolutivos

Los resultados confirman que el algoritmo genético es capaz de aproximarse a los mínimos globales de ambos problemas en múltiples dimensiones. Como era de esperar, Rastrigin mostró mayor variabilidad en los valores de fitness debido a sus muchos mínimos locales, lo que implica que algunas ejecuciones del GA pueden quedarse atrapadas en óptimos locales alejados del global. En contraste, Rosenbrock (aunque es no convexa) tiende a un único valle principal; por ello, la mayoría de las corridas alcanzaron valores cercanos al mínimo global con menor dispersión. En general se observa que al aumentar la dimensión (de 2D a 3D) la tarea se complica y la media del fitness aumenta (peor óptimo encontrado), reflejando la maldición de la dimensionalidad. El uso de múltiples ejecuciones independientes es esencial para evaluar la robustez de los AG. Debido a su naturaleza estocástica, cada ejecución puede converger a soluciones distintas. Al analizar la media y desviación estándar de los fitness finales se obtiene una medida de fiabilidad del algoritmo: una baja desviación indica resultados consistentes. En la literatura sobre algoritmos genéticos se reconoce que en muchos casos una sola ejecución puede no ser representativa​jstatsoft.org. Aunque un análisis comparativo profundo (p.ej., usando poblaciones más grandes o múltiples corridas en paralelo) queda fuera del alcance de este documento, nuestros resultados ilustran este fenómeno. Este estudio es reproducible: todo el código R necesario está incluido, permitiendo a otros investigadores replicar los experimentos, variar parámetros del GA (tasa de cruce, mutación, tamaño de población, etc.) y comparar con otros algoritmos de optimización.:Conclusiones Se ha presentado una documentación completa de la optimización de las funciones de Rosenbrock y Rastrigin en 2D y 3D empleando algoritmos genéticos en R. Mediante visualizaciones 3D iniciales se ilustraron las características de cada función de prueba. Se implementó el paquete GA para resolver cada caso y se realizaron 30 ejecuciones independientes para evaluar la robustez. Los resultados muestran que el GA puede encontrar aproximaciones al mínimo global en ambos problemas, aunque la función Rastrigin (múltiples mínimos locales) presenta más variabilidad y dificultad, especialmente en 3D. # Conclusión General

Al terminar este trabajo, la verdad es que uno se da cuenta de lo poderosos y flexibles que pueden ser los algoritmos bioinspirados cuando se trata de resolver problemas de optimización, tanto numéricos como combinatorios. En la primera parte, experimentamos con funciones clásicas como Rosenbrock y Rastrigin usando métodos como el descenso de gradiente, PSO y algoritmos genéticos. Lo interesante fue ver cómo los métodos bioinspirados, inspirados en la naturaleza y el comportamiento colectivo, logran escapar de los mínimos locales y explorar el espacio de soluciones de una forma mucho más creativa y robusta que los métodos tradicionales. No solo es cuestión de encontrar el mínimo, sino de cómo se llega a él: la diversidad, la colaboración y la adaptación constante hacen la diferencia.

Pero la cosa no se quedó ahí. En la segunda parte, nos metimos de lleno en la optimización combinatoria, enfrentándonos al clásico problema del viajante usando colonia de hormigas. Aquí, la inspiración en el comportamiento de las hormigas para encontrar rutas óptimas en la naturaleza se tradujo en un algoritmo capaz de encontrar soluciones eficientes en problemas donde la cantidad de combinaciones posibles es abrumadora. Es impresionante ver cómo, a través de la cooperación y la comunicación indirecta (como las feromonas en el caso de las hormigas), el sistema encuentra caminos cada vez mejores, incluso cuando el espacio de búsqueda es gigantesco.

En resumen, este trabajo no solo nos permitió comparar y entender diferentes algoritmos, sino que también nos mostró la importancia de pensar “fuera de la caja” y de inspirarnos en la naturaleza para resolver problemas complejos. Los algoritmos bioinspirados no son una receta mágica, pero sí una herramienta poderosa y adaptable, capaz de enfrentar desafíos tanto en el mundo continuo como en el discreto. Además, trabajar con estos métodos fomenta la creatividad, el trabajo en equipo y una visión interdisciplinaria que, sin duda, es clave en la ciencia y la ingeniería de hoy.

Parte 2. Optimización combinatoria

2.1 Planteamiento del problema

Este trabajo resuelve el problema del viajero (TSP) para un vendedor que debe visitar 13 ciudades principales de Colombia, optimizando la ruta mediante Ant Colony Optimization (ACO) y Algoritmos Genéticos (GA). Los costos totales se calculan considerando: - Tiempo del vendedor: Costos por hora de $30,000, $50,000 y $70,000 COP, con una velocidad promedio de 60 km/h. - Peajes: Costos exactos basados en datos de INVIAS y colombiapeajes.com, ajustados al 10% de incremento para abril de 2025. - Combustible: Vehículo DFSK C35 con rendimiento de 10 km/litro y gasolina a $16,000 COP/galón.

La solución óptima se visualiza con un GIF animado que muestra un carrito recorriendo las carreteras principales entre las ciudades.

# Definimos las 13 ciudades principales con sus coordenadas geográficas.
ciudades <- data.frame(
  Ciudad = c("Bogotá", "Medellín", "Cali", "Barranquilla", "Cartagena", "Bucaramanga", 
             "Pereira", "Cúcuta", "Ibagué", "Manizales", "Santa Marta", "Villavicencio", "Pasto"),
  Latitud = c(4.6097, 6.2518, 3.4372, 10.9685, 10.3997, 7.1254, 4.8133, 7.8939, 
              4.4389, 5.0689, 11.2408, 4.1420, 1.2136),
  Longitud = c(-74.0817, -75.5638, -76.5225, -74.7813, -75.5144, -73.1198, -75.6961, 
               -72.5078, -75.2322, -75.5174, -74.1990, -73.6266, -77.2811)
)
#Usamos una matriz de distancias (en km) basada en rutas principales por carretera.
distancias <- matrix(c(
  0, 426, 460, 1002, 1068, 384, 306, 552, 174, 257, 1008, 165, 893,
  426, 0, 418, 876, 941, 463, 142, 628, 328, 166, 886, 595, 774,
  460, 418, 0, 1138, 1203, 595, 259, 760, 296, 341, 1144, 627, 416,
  1002, 876, 1138, 0, 122, 618, 1016, 664, 1176, 1019, 122, 837, 1365,
  1068, 941, 1203, 122, 0, 683, 1081, 729, 1241, 1084, 187, 902, 1430,
  384, 463, 595, 618, 683, 0, 458, 168, 558, 401, 624, 419, 1017,
  306, 142, 259, 1016, 1081, 458, 0, 623, 323, 24, 1026, 590, 769,
  552, 628, 760, 664, 729, 168, 623, 0, 726, 566, 672, 587, 1185,
  174, 328, 296, 1176, 1241, 558, 323, 726, 0, 247, 1182, 339, 729,
  257, 166, 341, 1019, 1084, 401, 24, 566, 247, 0, 1029, 432, 712,
  1008, 886, 1144, 122, 187, 624, 1026, 672, 1182, 1029, 0, 843, 1371,
  165, 595, 627, 837, 902, 419, 590, 587, 339, 432, 843, 0, 858,
  893, 774, 416, 1365, 1430, 1017, 769, 1185, 729, 712, 1371, 858, 0
), nrow=13, byrow=TRUE)
rownames(distancias) <- colnames(distancias) <- ciudades$Ciudad

El objetivo de este problema es optimizar con respecto a los costos y no a las distancias entre ciudades, por lo que se tienen que considerar los costos de combustible, de peajes y cuánto cobra el vendedor por hora de trabajo. Sin embargo, la distancia afectará al valor de todos estos costos, y por lo tanto hay que considerarla. Adicionalmente, todos estos costos están en función de la distancia en metros, por lo que es necesario realizar la conversión de latitud-longitud a coordenadas en metros. Para esto se usó la librería “sf” para realizar la conversión al sistema de coordenadas planas UTM, el cual representa los puntos del globo en metros.

Luego, se crea la matriz de distancias en metros entre cada ciudad.

Ahora, hay que considerar los costos para poder crear una matriz de costos para resolver el problema de optimización.

Con respecto al costo del combustible, este dependerá del vehículo que el vendedor utilizará para realizar las entregas. Para este problema, se utilizará un furgón DFSK C35, el cual tiene un consumo de combustible de 7.6 litros aproximado por cada 100 Km de recorrido, que se puede traducir en 0.000076 litros por cada 1 metro (DFSK, s.f., Especificaciones Furgon C35). Adicionalmente, se considera el precio promedio de la gasolina en Colombia que, segun (La República, 2025), tiene un valor de $15.827 pesos colombianos por galón, que se puede traducir en $4.022 pesos colombianos por litro aproximadamente.

gasto_litro_por_metro <- 0.000076
precio_gasolina_por_litro <- 4.022 
costos_combustible <- distancias * gasto_litro_por_metro * precio_gasolina_por_litro
rownames(costos_combustible) <- nombre_ciudades
colnames(costos_combustible) <- nombre_ciudades
print(costos_combustible)

Considerando el costo de los peajes, se usarán los datos de (Invias, 2024) y (Mintransporte, 2025) para calcular el valor promedio de cada peaje de las ciudades consideradas y se asumirá que el vendedor pagará el valor promedio del peaje de la ciudad de origen y de la ciudad de destino exactamente 1 vez cada que las recorra.

#Matriz de costos totales de peajes (en COP), basada en datos reales ajustados al ~10% de incremento para abril de 2025.
costo_peajes <- matrix(c(
  0, 60000, 65000, 100000, 110000, 65000, 40000, 70000, 25000, 40000, 100000, 40000, 90000,  # Bogotá
  60000, 0, 55000, 90000, 100000, 65000, 30000, 80000, 40000, 30000, 90000, 80000, 80000,  # Medellín
  65000, 55000, 0, 130000, 140000, 90000, 40000, 100000, 40000, 50000, 130000, 80000, 50000,  # Cali
  100000, 90000, 130000, 0, 21800, 80000, 120000, 90000, 140000, 120000, 21800, 90000, 170000,  # Barranquilla
  110000, 100000, 140000, 21800, 0, 90000, 130000, 100000, 150000, 130000, 43600, 100000, 180000,  # Cartagena
  65000, 65000, 90000, 80000, 90000, 0, 80000, 25000, 80000, 65000, 80000, 50000, 130000,  # Bucaramanga
  40000, 30000, 40000, 120000, 130000, 80000, 0, 90000, 25000, 15000, 120000, 65000, 80000,  # Pereira
  70000, 80000, 100000, 90000, 100000, 25000, 90000, 0, 90000, 80000, 90000, 65000, 140000,  # Cúcuta
  25000, 40000, 40000, 140000, 150000, 80000, 25000, 90000, 0, 25000, 140000, 40000, 80000,  # Ibagué
  40000, 30000, 50000, 120000, 130000, 65000, 15000, 80000, 25000, 0, 120000, 50000, 65000,  # Manizales
  100000, 90000, 130000, 21800, 43600, 80000, 120000, 90000, 140000, 120000, 0, 90000, 170000,  # Santa Marta
  40000, 80000, 80000, 90000, 100000, 50000, 65000, 65000, 40000, 50000, 90000, 0, 120000,  # Villavicencio
  90000, 80000, 50000, 170000, 180000, 130000, 80000, 140000, 80000, 65000, 170000, 120000, 0   # Pasto
), nrow=13, byrow=TRUE)
rownames(costo_peajes) <- colnames(costo_peajes) <- ciudades$Ciudad

Por último, se debe de considerar el salario por horas promedio de un vendedor que haga dichos recorridos para entregar los pedidos. Adicional a ser vendedor, esta persona realizará las entregas y la conducción de la mercancía, por lo que también hay que considerar su pago como transportista. Dicho esto, se promediaron salarios de un transportista y un vendedor para poder determinar el salario final de la persona. Según (Talent.com, s.f., Salario medio para Transporte De Carga en Colombia 2025) y (Talent.com, s.f., Salario medio para Vendedor en Colombia 2025), un transportista gana en promedio $9.341 pesos colombianos la hora y un vendedor hace $7.144 la hora; por lo tanto, el salario a utilizar será el $8.242 pesos la hora.

Asumiendo que el vendedor conducirá a una velocidad media de 50 km/h al día, que se podrían traducir en 50000 m/h para facilitar cálculos, se procede a calcular el tiempo de viaje y, junto con esto, cuánto se le pagará al vendedor por cada viaje.

velocidad_media_metros_por_hora <- 50000
salario_vendedor_colombia <- 7144
salario_transportista_colombia <- 9341
salario_final <- (salario_vendedor_colombia + salario_transportista_colombia)/2
costos_vendedor <- distancias*(1/velocidad_media_metros_por_hora)*salario_final
rownames(costos_vendedor) <- nombre_ciudades
colnames(costos_vendedor) <- nombre_ciudades
costos_vendedor

Concluyendo, la matriz de costos simplemente sería el resultado de la suma de las anteriores matrices previamente definidas, y esta será la matriz que se utilizarán en los distintos algoritmos para encontrar la mejor ruta.

Se calculan los costos totales considerando - Tiempo : Velocidad promedio de 60 km/h, - Costos por hora $30,000,$50,000,$70,000 COP. - Combustible: DFSK C35 con 10km/litro, gasolina a $16,000 COP/galon.

# Costo de combustible
costo_combustible_km <- 16000 / (10 * 3.785)  # ≈ 422.72 COP/km
# Fuente: Precio estimado para 2025, rendimiento DFSK C35 (especificaciones del fabricante)

# Función para calcular costos
calcular_costos <- function(costo_hora) {
  tiempos <- distancias / 60  # Tiempo en horas
  costo_tiempo <- tiempos * costo_hora
  costo_combustible <- distancias * costo_combustible_km
  costo_total <- costo_tiempo + costo_combustible + costo_peajes
  return(costo_total)
}

# Calcular matrices de costos
costo_hora <- c(30000, 50000, 70000)
matrices_costos <- lapply(costo_hora, calcular_costos)


## 2.2 Implementación Método de Colonia de hormigas Se implementa Ant Colony Optimizacion(ACO) para optimizar TSP.
Este Algoritmo (ACO) esta inspirado en el comportamiento de hormigas,este algoritmo simula como las hormigas encuentran la ruta mas corta dejando feromonas. la idea en si es que la ruta mas corta acumulara mas feromonas con el tiempo.

aco_tsp <- function(costo_matriz, n_ants=100, alpha=1, beta=2, rho=0.1, max_iter=200) {
  n <- nrow(costo_matriz)
  pheromones <- matrix(1, nrow=n, ncol=n)
  best_tour <- NULL # Almacena la mejor ruta encontrada
  best_cost <- Inf # Almacena el costo mínimo inicial (infinito)
  history <- list() # Registra el progreso de las iteraciones
  
  for (iter in 1:max_iter) {                  # Bucle principal para iteraciones (máximo 200)
    tours <- matrix(NA, nrow=n_ants, ncol=n)  # Matriz para almacenar rutas de todas las hormigas
    costs <- numeric(n_ants)                  # Vector para costos de cada hormiga
    
    for (ant in 1:n_ants) {               # Simula el movimiento de cada hormiga (100 por iteración)
      current <- sample(1:n, 1)           # Comienza en una ciudad aleatoria
      tour <- current                     # Inicializa la ruta con la ciudad actual
      visited <- rep(FALSE, n)            # Marca ciudades visitadas
      visited[current] <- TRUE
      
      for (i in 1:(n-1)) {                                                             # Construye la ruta visitando todas las ciudades
        probs <- (pheromones[current,] ^ alpha) * ((1 / costo_matriz[current,]) ^ beta)
        probs[visited] <- 0                                                            
        probs <- probs / sum(probs)
        next_city <- sample(1:n, 1, prob=probs)                                         # Normaliza probabilidades
        tour <- c(tour, next_city)
        visited[next_city] <- TRUE
        current <- next_city
      }
      
      # Asignar tour sin el retorno (longitud n)
      tours[ant,] <- tour[1:n]  # Tomamos solo las n ciudades
      
      # Calcular costo incluyendo el retorno a la ciudad inicial
      tour_with_return <- c(tour, tour[1])
      cost <- sum(costo_matriz[cbind(tour_with_return[-n-1], tour_with_return[-1])])
      costs[ant] <- cost
      
      if (cost < best_cost) {
        best_cost <- cost
        best_tour <- tour_with_return
      }
    }
    
    # Actualizar feromonas
    pheromones <- pheromones * (1 - rho)
    for (ant in 1:n_ants) {
      tour_with_return <- c(tours[ant,], tours[ant,1])  # Cerrar el ciclo para feromonas
      pheromones[cbind(tour_with_return[-n-1], tour_with_return[-1])] <- 
        pheromones[cbind(tour_with_return[-n-1], tour_with_return[-1])] + 1 / costs[ant]
    }
    
    history[[iter]] <- list(tour=best_tour, cost=best_cost)
  }
  
  return(list(best_tour=best_tour, best_cost=best_cost, history=history))
}

2.3 Implementación Método de Algoritmos Genéticos

Se utiliza el paquete de GA para optimizar el TSP. Acá se usa el Algoritmo Genético(GA) esta inspirado en la evolución y selección natural. Este algoritmo evoluciona una población de soluciones(rutas) mediante cruzamiento y mutación la “aptitud” mide que tan buena es una ruta y las mejores rutas se van combinando para mejorar.

# Número de ciudades
n_ciudades <- 13

# Función para normalizar la matriz de costos, ya que search_tour_ants
# funciona con valores normalizados.
# Se optó por usar normalización zscore.
normalize_zscore <- function(m) {
  (m - mean(m)) / sd(m)
}

# Normalización de matriz de costos
matriz_costos_normalizada <- normalize_zscore(matriz_costos)

# Ejecución del método de colonia de hormigas
recorrido_optimizado <- search_tour_ants(matriz_costos_normalizada, n_ciudades, K = 80, N = 40, log=TRUE)
print("MEJOR RECORRIDO: ")
print(recorrido_optimizado$tour)

A partir de lo anterior se pudo crear el siguiente mapa de rutas que muestra las mejores rutas calculadas por los algoritmos previamente implementados.

Figura 12. Animación de la mejor ruta del vendedor

Animación de la mejor ruta del vendedor

Figura 13. Comparación de costos óptimos: ACO vs GA
Figura 13. Comparación de costos óptimos: ACO vs GA

Comparación de costos óptimos: ACO vs GA

Figura 14. Comparación de costos óptimos: ACO vs GA
Figura 14. Comparación de costos óptimos: ACO vs GA

Desglose de costos

Por último, en la Figura 13 y Figura 14 respectivamente se muestran tanto la comparación de costos óptimos para ambos métodos utilizados como el desglose de los costos para la mejor ruta, donde evidentemente se puede ver que ambos métodos tienen un rendimiento similar y que el 60% de los costos se van en el pago de los peajes.

2.4 Conclusiones

El problema del viajero (TSP) para las 13 ciudades principales de Colombia se pudo resolver de manera satisfactoria utilizando Ant Colony Optimization(ACO) y Algoritmos Genéticos(GA). los principales hallazgos son: - Rutas óptimas: La mejor ruta para un costo por hora de $50,000 fue (ver GIF), con un costo total de $6.066.327 COP.Los peajes representan aproximadamente el (60.1%)del costo total, seguidos por el combustible (9.5%) y el tiempo (30.5%) - Desempeño de los algoritmos: ACO mostró una convergencia más rápida en las primeras 50 iteraciones, mientras que GA exploró un espacio de soluciones más amplio, sugiriendo que GA es más robusto para problemas complejos. - Impacto del costo por hora: Aumentar el costo por hora de $30,000 a $70,000 incrementó el costo total en [ver tabla]%, pero el orden de las ciudades permaneció estable, indicando que los costos fijos (peajes y combustible) dominan. - Visualización mejorada: La animación del carrito recorriendo carreteras principales mejora la interpretación de la ruta óptima, mostrando un recorrido realista basado en datos de OSRM.

Los algoritmos bioinspirados son efectivos, pero requieren calibración.Ademas la visualización animada con rutas reales y un carrito mejora la comunicación de resultados. y permite entender mejor el modelo. La precisión de los datos (distancias, peajes, rutas) es crítica para aplicaciones industriales.

Conclusión General

Al terminar este trabajo, la verdad es que uno se da cuenta de lo poderosos y flexibles que pueden ser los algoritmos bioinspirados cuando se trata de resolver problemas de optimización, tanto numéricos como combinatorios. En la primera parte, experimentamos con funciones clásicas como Rosenbrock y Rastrigin usando métodos como el descenso de gradiente, PSO y algoritmos genéticos. Lo interesante fue ver cómo los métodos bioinspirados, inspirados en la naturaleza y el comportamiento colectivo, logran escapar de los mínimos locales y explorar el espacio de soluciones de una forma mucho más creativa y robusta que los métodos tradicionales. No solo es cuestión de encontrar el mínimo, sino de cómo se llega a él: la diversidad, la colaboración y la adaptación constante hacen la diferencia.

Pero la cosa no se quedó ahí. En la segunda parte, nos metimos de lleno en la optimización combinatoria, enfrentándonos al clásico problema del viajante usando colonia de hormigas. Aquí, la inspiración en el comportamiento de las hormigas para encontrar rutas óptimas en la naturaleza se tradujo en un algoritmo capaz de encontrar soluciones eficientes en problemas donde la cantidad de combinaciones posibles es abrumadora. Es impresionante ver cómo, a través de la cooperación y la comunicación indirecta (como las feromonas en el caso de las hormigas), el sistema encuentra caminos cada vez mejores, incluso cuando el espacio de búsqueda es gigantesco.

En resumen, este trabajo no solo nos permitió comparar y entender diferentes algoritmos, sino que también nos mostró la importancia de pensar “fuera de la caja” y de inspirarnos en la naturaleza para resolver problemas complejos. Los algoritmos bioinspirados no son una receta mágica, pero sí una herramienta poderosa y adaptable, capaz de enfrentar desafíos tanto en el mundo continuo como en el discreto. Además, trabajar con estos métodos fomenta la creatividad, el trabajo en equipo y una visión interdisciplinaria que, sin duda, es clave en la ciencia y la ingeniería de hoy.

Reporte de contribución individual

- Leonardo Federico Corona Torres

  • Apoyo en redacción y realización de implementaciones de sección “Método de algoritmos evolutivos”.

  • Apoyo en redacción de implementaciones de graficación en Parte 2 del reporte.

  • Búsqueda e investigación de funciones de prueba a utilizar.

  • Apoyo en redacción y realización de implementaciones de sección “Selección e implementación de las funciones de prueba”.

- David Escobar Ruiz

  • Definición y escritura de estructura del reporte.

  • Apoyo en redacción y realización de implementaciones de sección “Selección e implementación de las funciones de prueba”.

  • Apoyo en redaccióny realización de implementaciones de sección “Método de optimización de partículas”.

  • Apoyo en redacción y realización de implementaciones de métodos, planteamiento y preprocesamiento de datos Parte 2 del reporte.

- Johan Sebastián Robles Rincón

  • Implementación y prueba del método de evolución diferencial en R para funciones de Rosenbrock y Rastrigin en 2D y 3D.

  • Análisis de resultados numéricos y gráficos.

  • Apoyo en redacción de sección del contenido técnico relacionado con este método de evolucion diferencial en el informe.

- Sebastian Soto Arcila

  • Apoyo en redacción y realización de implementaciones de sección “Método de optimización por descenso de gradiente”

  • Apoyo en redacción de sección “Selección e implementación de las funciones de prueba”.

Repositorio de GitHub del proyecto

https://github.com/druiz35/RNABI2025-1-Equipo3/

Bibliografía

Autofact. (2024). Peajes en Colombia: Conoce sus ubicaciones y precios 2024. https://www.autofact.com.co/blog/mi-carro/peajes/peajes-colombia-precios

DFSK. (s.f.). Especificaciones Furgon C35. Recuperado el 2 de mayo de 2025, de http://static.multiaviso.com/vehicle/specs/22-VRZC564XLBE6-dfsk-otros-modelos-2017-furgon-c35.pdf

INVIAS. (s.f.). Sistema de información vial. https://hermes.invias.gov.co/viajeroseguro/

La República. (2025). PRECIO DE LA GASOLINA. Recuperado el 2 de mayo de 2025, de https://www.larepublica.co/precio-de-la-gasolina

Mintransporte. (2025). Colombiapeajes. https://colombiapeajes.com/

Molga, Smutnicki. (2005). Test functions for optimization needs. https://robertmarks.org/Classes/ENGR5358/Papers/functions.pdf

Talent.com. (s.f.). Salario medio para Transporte De Carga en Colombia 2025. Recuperado el 2 de mayo de 2025, de https://co.talent.com/salary?job=transporte+de+carga

Talent.com. (s.f.). Salario medio para Vendedor en Colombia 2025. Recuperado el 2 de mayo de 2025, de https://co.talent.com/salary?job=vendedor

ViaMichelin. (s.f.). Distancias estimadas con ViaMichelin. https://www.viamichelin.com/

Wikipedia. (s.f.). Test functions for optimization. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Test_functions_for_optimization

Wikipedia. (s.f.). Rosenbrock function. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Rosenbrock_

Wikipedia. (s.f.). Rastrigin function. Wikipedia. Recuperado el 2 de mayo de 2025, de https://en.wikipedia.org/wiki/Rastrigin_function

X.-S. Yang, Test problems in optimization, in: Engineering Optimization: An Introduction with Metaheuristic Applications (Eds Xin-She Yang), John Wiley & Sons, (2010)

LS0tDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQotLS0NCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IGZhbHNlDQogICAgY3NzOiBhcGFfc3R5bGUuY3NzDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IGZhbHNlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KYGBgez1odG1sfQ0KPCEtLQ0KICBOT1RFOiBFc3RlIGPDs2RpZ28gc2UgZWplY3V0YSwgcGVybyBubyBzZSBtdWVzdHJhIG5pIGVsIGPDs2RpZ28gbmkgbGEgc2FsaWRhDQotLT4NCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiMgRXN0YSBmdW5jacOzbiBtdWVzdHJhIGxhIHRhYmxlIGd1YWRhZGEgZW4gdW4gQ1NWDQojICAgcnV0YTogZGlyZWNjacOzbiBkZWwgY3N2DQpzaG93X3RhYmxlIDwtIGZ1bmN0aW9uKHJ1dGEpIHsNCiAgIyBMZWVyIGVsIENTVg0KICB0YWJsYV9jb21wbGV0YSA8LSByZWFkLmNzdihydXRhKQ0KICANCiAgIyBTZWxlY2Npb25hciBjYWRhIDEwIGZpbGFzICgxLCAxMSwgMjEsIC4uLikNCiAgZmlsYXNfY2FkYV8xMCA8LSBzZXEoMCwgbnJvdyh0YWJsYV9jb21wbGV0YSksIGJ5ID0gMTApDQogIHRhYmxhX2NhZGFfMTAgPC0gdGFibGFfY29tcGxldGFbZmlsYXNfY2FkYV8xMCwgXQ0KICBwcmludCh0YWJsYV9jYWRhXzEwKQ0KfQ0KYGBgDQoNCjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsgY29sb3I6IGJsYWNrOyBtYXJnaW4tdG9wOiA2MHB4OyJ9DQo8aDE+UkVQT1JURSBUUkFCQUpPIDE6IFNPTFVDScOTTiBERSBQUk9CTEVNQVMgREUgT1BUSU1JWkFDScOTTiBDT04gTcOJVE9ET1MgSEVVUsONU1RJQ09TPC9oMT4NCg0KPGgyPlJFREVTIE5FVVJPTkFMRVMgWSBBTEdPUklUTU9TIEJJT0lOU1BJUkFET1M8L2gyPg0KDQo8YnI+PGJyPjxicj4NCg0KPHA+PHN0cm9uZz5QcmVzZW50YWRvIHBvcjo8L3N0cm9uZz48L3A+DQoNCjxwPkxlb25hcmRvIEZlZGVyaWNvIENvcm9uYSBUb3JyZXM8YnI+IERhdmlkIEVzY29iYXIgUnVpejxicj4gYEpvaGFuIFNlYmFzdGlhbiBSb2JsZXMgUmluY8Ozbjxicj5gez1odG1sfVNlYmFzdGnDoW4gU290byBBcmNpbGE8L3A+DQoNCjxicj48YnI+DQoNCjxwPjxzdHJvbmc+UHJvZmVzb3I6PC9zdHJvbmc+IEp1YW4gRGF2aWQgT3NwaW5hIEFyYW5nbzwvcD4NCg0KPHA+PHN0cm9uZz5Nb25pdG9yOjwvc3Ryb25nPiBBbmRyw6lzIE1hdXJpY2lvIFphcGF0YSBSaW5jw7NuPC9wPg0KDQo8YnI+IDxpbWcgc3JjPSJsb2dvX3VuYWwucG5nIiBhbHQ9IlVuaXZlcnNpdHkgTG9nbyIgd2lkdGg9IjEwMHB4Ii8+IDxicj48YnI+DQoNCjxwPlVuaXZlcnNpZGFkIE5hY2lvbmFsIGRlIENvbG9tYmlhPGJyPiBGYWN1bHRhZCBkZSBNaW5hczxicj4gSW5nZW5pZXLDrWEgZGUgU2lzdGVtYXMgZSBJbmZvcm3DoXRpY2E8L3A+DQoNCjxwPjxzdHJvbmc+YHIgZm9ybWF0KFN5cy5EYXRlKCksICIlZCBkZSAlQiBkZSAlWSIpYDwvc3Ryb25nPjwvcD4NCjo6Og0KDQpgYGB7PWh0bWx9DQo8IS0tDQogIE5PVEU6IExvcyB0aXBvcyBkZSBzZWxlY3RvcmVzIHNvbjoNCiAgICAtIENvbWVuemFkb3MgZW4gIml1IiBwYXJhIGl0ZW1zIGRlIGxpc3RhcyBubyBvcmRlbmFkYXMNCiAgICAtIENvbWVuemFkb3MgZW4gImlvIiBwYXJhIGl0ZW1zIGRlIGxpc3RhcyBvcmRlbmFkYXMNCi0tPg0KYGBgDQoNCiMgQ29udGVuaWRvcw0KDQotICAgW0ludHJvZHVjY2nDs25dKCNpdTEuKQ0KLSAgIFtNZXRvZG9sb2fDrWFdKCNpdTIuKQ0KLSAgIFsxLiBPcHRpbWl6YWNpw7NuIG51bcOpcmljYV0oI2lvMS4pDQotICAgWzEuMS4gU2VsZWNjacOzbiBlIGltcGxlbWVudGFjacOzbiBkZSBsYXMgZnVuY2lvbmVzIGRlIHBydWViYV0oI2lvMS4xLikNCi0gICBbMS4xLjEuIEJyZXZlIGV4cGxpY2FjacOzbiBkZSBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSBwYXJhIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuXSgjaW8xLjEuMS4pDQotICAgWzEuMS4yLiBJbXBsZW1lbnRhY2nDs24gZGUgZnVuY2lvbmVzIGRlIGdyYWZpY2FjacOzbl0oI2lvMS4xLjIpDQotICAgWzEuMS4zLiBGdW5jacOzbiBkZSBSb3NlbmJyb2NrXSgjaW8xLjEuMy4pDQotICAgWzEuMS40LiBGdW5jacOzbiBkZSBSYXN0cmlnaW5dKCNpbzEuMS40LikNCi0gICBbMS4yLiBNw6l0b2RvIGRlIGRlc2NlbnNvIGRlIGdyYWRpZW50ZV0oI2lvMS4yLikNCi0gICBbMS4yLjEuIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIGRlc2NlbnNvIHBvciBncmFkaWVudGVdKCNpbzEuMi4xLikNCi0gICBbMS4yLjIuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjIuMi4pDQotICAgWzEuMi4zLiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMyBkaW1lbnNpb25lc10oI2lvMS4yLjMuKQ0KLSAgIFsxLjIuNC4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiBkaW1lbnNpb25lc10oI2lvMS4yLjQuKQ0KLSAgIFsxLjIuNS4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMyBkaW1lbnNpb25lc10oI2lvMS4yLjUuKQ0KLSAgIFsxLjIuNi4gQ29uY2x1c2lvbmVzIG3DqXRvZG8gZGUgZGVzZW5zbyBkZWwgZ3JhZGllbnRlXSgjaW8xLjIuNi4pDQotICAgWzEuMy4gTcOpdG9kbyBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsXSgjaW8xLjMuKQ0KLSAgIFsxLjMuMS4gSW1wbGVtZW50YWNpw7NuIGVuIFIgZGUgZXZvbHVjacOzbiBkaWZlcmVuY2lhbF0oI2lvMS4zLjEuKQ0KLSAgIFsxLjMuMi4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuMy4yLikNCi0gICBbMS4zLjMuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjMuMy4pDQotICAgWzEuMy40LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjMuNC4pDQotICAgWzEuMy41LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjMuNS4pDQotICAgWzEuMy42LiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsXSgjaW8xLjMuNi4pDQotICAgWzEuNC4gTcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzXSgjaW8xLjQuKQ0KLSAgIFsxLjQuMS4gSW1wbGVtZW50YWNpw7NuIGVuIFIgZGUgb3B0aW1pemFjacOzbiBkZSBwYXJ0w61jdWxhc10oI2lvMS40LjEuKQ0KLSAgIFsxLjQuMi4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXNdKCNpbzEuNC4yLikNCi0gICBbMS40LjMuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjQuMy4pDQotICAgWzEuNC40LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjQuNC4pDQotICAgWzEuNC41LiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzXSgjaW8xLjQuNS4pDQotICAgWzEuNC42LiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsXSgjaW8xLjQuNi4pDQotICAgWzEuNS4gTcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3NdKCNpbzEuNS4pDQotICAgWzEuNS4xLiBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3NdKCNpbzEuNS4xLikNCi0gICBbMS41LjIuIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAyIGRpbWVuc2lvbmVzXSgjaW8xLjUuMi4pDQotICAgWzEuNS4zLiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMyBkaW1lbnNpb25lc10oI2lvMS41LjMuKQ0KLSAgIFsxLjUuNC4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiBkaW1lbnNpb25lc10oI2lvMS41LjQuKQ0KLSAgIFsxLjUuNS4gT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMyBkaW1lbnNpb25lc10oI2lvMS41LjUuKQ0KLSAgIFsxLjUuNi4gQ8OhbGN1bG8gZGUgZXN0YWTDrXN0aWNhcyB5IGFuw6FsaXNpc10oI2lvMS41LjYuKQ0KLSAgIFsxLjUuNy4gQ29uY2x1c2lvbmVzIG3DqXRvZG8gZGUgYWxnb3JpdG1vcyBldm9sdXRpdm9zXSgjaW8xLjUuNy4pDQotICAgWzIuIE9wdGltaXphY2nDs24gY29tYmluYXRvcmlhXSgjaW8yLikNCi0gICBbMi4xLiBQbGFudGVhbWllbnRvIGRlbCBwcm9ibGVtYV0oI2lvMi4xLikNCi0gICBbMi4yLiBJbXBsZW1lbnRhY2nDs24gTcOpdG9kbyBkZSBDb2xvbmlhIGRlIGhvcm1pZ2FzXSgjaW8yLjIuKQ0KLSAgIFsyLjMuIEltcGxlbWVudGFjacOzbiBNw6l0b2RvIGRlIEFsZ29yaXRtb3MgR2Vuw6l0aWNvc10oI2lvMi4zLikNCi0gICBbMi41LiBDb25jbHVzaW9uZXNdKCNpbzIuNC4pDQotICAgW0NvbmNsdXNpw7NuIEdlbmVyYWxdKCNpbzUuKQ0KLSAgIFtSZXBvcnRlIGRlIGNvbnRyaWJ1Y2nDs24gaW5kaXZpZHVhbF0oI2l1My4pDQotICAgW1JlcG9zaXRvcmlvIGRlIEdpdEh1YiBkZWwgcHJveWVjdG9dKCNpdTQuKQ0KLSAgIFtCaWJsaW9ncmFmw61hXSgjaXU1LikNCg0KPGEgbmFtZT0iaXUxLiI+PC9hPg0KDQojIEludHJvZHVjY2nDs24NCg0KRWwgcHJlc2VudGUgdHJhYmFqbyB0cmF0YSBhbGd1bm9zIGRlIGxvcyBtw6l0b2RvcyBtw6FzIHJlbGV2YW50ZXMgZGUgb3B0aW1pemFjacOzbiBudW3DqXJpY2EgYmFzYWRhIGVuIG1hbmlwdWxhY2lvbmVzIGRlbCBncmFkaWVudGUgZGUgdW5hIGZ1bmNpw7NuIG9iamV0aXZvIChmdW5jacOzbiBhIG9wdGltaXphcikgeSB0YW1iacOpbiBhbGdvcml0bW9zIGhldXLDrXN0aWNvcyBiYXNhZG9zIGVuIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhIG5hdHVyYWxlemEsIGNvbW8gbG8gc29uIGxvcyBhbGdvcml0bW9zIGV2b2x1dGl2b3MuIFRvZG9zIGVzdG9zIG3DqXRvZG9zIHB1ZWRlbiBsbGVnYXIgYSBzZXIgw7p0aWxlcyBlbiBkaXN0aW50b3MgY29udGV4dG9zIGVuIGxvcyBxdWUgc2UgYnVzY2Egb3B0aW1pemFyIHVuYSBmdW5jacOzbiBwYXJhIGFsZ8O6biBmaW4sIGNvbW8gZW5jb250cmFyIGxhIG1lam9yIHJ1dGEgZW50cmUgY2l1ZGFkZXMgbyBvcHRpbWl6YXIgdW5hIGZ1bmNpw7NuIGRlIHDDqXJkaWRhIGVuIHVuIGNvbnRleHRvIGRlIGFwcmVuZGl6YWplIGRlIG3DoXF1aW5hLiBDYWRhIG3DqXRvZG8gdGllbmUgcGFydGljdWxhcmlkYWRlcyBpbnRlcmVzYW50ZXMgcXVlIHNlIHZhbiBhIGV4cGxvcmFyIGRlIG1hbmVyYSBnZW5lcmFsIHBvciBtZWRpbyBkZSB1bmEgYnJldmUgaW1wbGVtZW50YWNpw7NuIHkgZWplY3VjacOzbiBjb24gZG9zIGZ1bmNpb25lcyBtdXkgdXRpbGl6YWRhcyBwYXJhIHByb2JhciBhbGdvcml0bW9zIGRlIG9wdGltaXphY2nDs246IGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgeSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4uDQoNCjxhIG5hbWU9Iml1Mi4iPjwvYT4NCg0KIyBNZXRvZG9sb2fDrWENCg0KUGFyYSBpbXBsZW1lbnRhciB5IGRvY3VtZW50YXIgbGEgb3B0aW1pemFjacOzbiBzZSBlbXBsZWEgUiBNYXJrZG93biwgY29tYmluYW5kbyBjw7NkaWdvIFIgeSB0ZXh0byBleHBsaWNhdGl2by4gU2UgdXRpbGl6YW4gbGlicmVyw61hcyBwYXJhIHJlbmRlcml6YXIgZ3LDoWZpY29zIHkgYW5pbWFjaW9uZXMsIGxpYnJlcsOtYXMgcGFyYSBpbXBsZW1lbnRhciBsb3MgbcOpdG9kb3MgaGV1csOtc3RpY29zIHkgbGlicmVyw61hcyBwYXJhIG1hbmlwdWxhciBsb3MgZGF0b3MuIFBhcmEgbG9zIGNhc29zIDNEICh0cmVzIHZhcmlhYmxlcykgZXMgZGlmw61jaWwgdmlzdWFsaXphciBkaXJlY3RhbWVudGUgbGEgZnVuY2nDs24gZGUgMyBkaW1lbnNpb25lcyAoZXNwYWNpbyBkZSA0IHZhcmlhYmxlcyksIHBvciBsbyBxdWUgc2UgbW9zdHJhcsOhbiDDum5pY2FtZW50ZSBsb3MgcHVudG9zIMOzcHRpbW9zIGFsY2FuemFkb3MuDQoNCjxhIG5hbWU9ImlvMS4iPjwvYT4NCg0KIyBQYXJ0ZSAxLiBPcHRpbWl6YWNpw7NuIG51bcOpcmljYQ0KDQo8YSBuYW1lPSJpbzEuMS4iPjwvYT4NCg0KIyMgMS4xIFNlbGVjY2nDs24gZSBpbXBsZW1lbnRhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmENCg0KUGFyYSBvYnNlcnZhciBlbCBjb21wb3J0YW1pZW50byBkZSBjYWRhIHVubyBkZSBsb3MgbcOpdG9kb3MgZGUgb3B0aW1pemFjacOzbiBpbXBsZW1lbnRhZG9zLCBzZSBvcHTDsyBwb3IgbGEgc2VsZWNjacOzbiBkZSBkb3MgZnVuY2lvbmVzIGRlIHBydWViYSBlc3TDoW5kYXIgcGFyYSBldmFsdWFyIGFsZ29yaXRtb3MgZGUgb3B0aW1pemFjacOzbjogRnVuY2nDs24gZGUgUm9zZW5icm9jayB5IEZ1bmNpw7NuIGRlIFJhc3RyaWdpbi4gRGViaWRvIGEgc3UgY29tcGxlamlkYWQsIGFtYmFzIGZ1bmNpb25lcyBzb24gaW5kaWNhZG9yZXMgw7p0aWxlcyBwYXJhIGNvbXBhcmFyIGxhIGVmaWNhY2lhIGRlIG9wdGltaXphZG9yZXMgY29tbyBsb3MgQUcuDQoNClByZXZpbyBhIGxhIGltcGxlbWVudGFjacOzbiBkZSBsb3MgYWxnb3JpdG1vcyBlbiBlbCBsZW5ndWFqZSBSIHkgcHJldmlvIGEgbGEgcmVjb3BpbGFjacOzbiBkZSByZXN1bHRhZG9zIHkgbGEgZGVyaXZhY2nDs24gZGUgY29uY2x1c2lvbmVzIGEgcGFydGlyIGRlIGVzdG9zLCBlbCBlcXVpcG8gZGVjaWRpw7MgcmVhbGl6YXIgdW5hIGJyZXZlIGludmVzdGlnYWNpw7NuIGdlbmVyYWwgZGUgbG8gcXVlIHNvbiBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSBwYXJhIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuLiBMYSBpbnZlc3RpZ2FjacOzbiBzZSByZWFsaXrDsyBkZSB0YWwgZm9ybWEgcXVlLCB1bmEgdmV6IGNvbmNsdcOtZGEsIHNlIHB1ZGllcmFuIGNvbXByZW5kZXIgbG9zIGNvbmNlcHRvcyBoYXN0YSBlbCBwdW50byBkZSBlc3RhciBlbiBsYXMgY2FwYWNpZGFkZXMgcmVzcG9uZGVyIGxhcyBzaWd1aWVudGVzIHByZWd1bnRhcyBpbXBsw61jaXRhbWVudGUgZW4gdW5hIGJyZXZlIHNlY2Npw7NuIGRlIGVzdGUgdHJhYmFqbzoNCg0KLSAgIMK/UXXDqSBlcyB1bmEgZnVuY2nDs24gZGUgcHJ1ZWJhIGVuIG9wdGltaXphY2nDs24/DQoNCi0gICDCv1BhcmEgcXXDqSBzZSB1dGlsaXphIHVuYSBmdW5jacOzbiBkZSBwcnVlYmEgZW4gb3B0aW1pemFjacOzbj8NCg0KLSAgIMK/Q8OzbW8gc2UgcHVlZGVuIGNsYXNpZmljYXIgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmE/DQoNCi0gICDCv0N1w6FsZXMgc29uIGFsZ3VuYXMgZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEgbcOhcyB1dGlsaXphZGFzPw0KDQpBIGNvbnRpbnVhY2nDs24gc2UgcHJlc2VudGEgZGljaGEgc2VjY2nDs24gcGFyYSBsdWVnbyBjb250aW51YXIgY29uIGVsIGVzdHVkaW8gbcOhcyBkZXRhbGxhZG8gZGUgbGFzIGZ1bmNpb25lcyBlc2NvZ2lkYXMuDQoNCjxhIG5hbWU9ImlvMS4xLjEuIj48L2E+DQoNCiMjIyAxLjEuMSBCcmV2ZSBleHBsaWNhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEgcGFyYSBwcm9ibGVtYXMgZGUgb3B0aW1pemFjacOzbg0KDQpTZWfDum4gKFlhbmcsIDIwMTApLCB1bmEgZnVuY2nDs24gZGUgcHJ1ZWJhIGVzIHVuYSBmdW5jacOzbiBjb24gdW5hcyBwcm9waWVkYWRlcyBlc3BlY2lhbGVzIHF1ZSBwZXJtaXRlIHByb2JhciBzaSBlbCByZW5kaW1pZW50byBkZSB1biBtw6l0b2RvIGRlIG9wdGltaXphY2nDs24gaW1wbGVtZW50YWRvIGVzIGFjZXB0YWJsZSBiYWpvIGxhcyBjb25kaWNpb25lcyBlc3BlY2lhbGVzIHF1ZSBpbXBvbmUgbGEgZnVuY2nDs24gZGUgcHJ1ZWJhLsKgDQoNCkVzdG8gZXMgZXNwZWNpYWxtZW50ZSDDunRpbCBwYXJhIHZlcmlmaWNhciBxdWUgZWwgbcOpdG9kbyBzZWEgZWZpY2llbnRlIGJham8gZGlzdGludGFzIGNvbmRpY2lvbmVzIGVuIGxhcyBxdWUgc2UgZXNwZXJhIHF1ZSBzZSBpbXBsZW1lbnRlLCBjb21vIHBvciBlamVtcGxvLCBjYXNvcyBlbiBsb3MgcXVlIGxhIGZ1bmNpw7NuIHRpZW5lIG3Dumx0aXBsZXMgbcOtbmltb3MgeS9vIG3DoXhpbW9zIGxvY2FsZXMuDQoNClNlZ8O6biAoTW9sZ2EsIDIwMDUpLCBsYXMgZnVuY2lvbmVzIGRlIHBydWViYSBzZSBwdWVkZW4gdWJpY2FyIGVuIHVuYSBkZSBsYXMgc2lndWllbnRlcyBjbGFzZXMsIHRvZGFzIHNpZW5kbyBmdW5jaW9uZXMgY29udGludWFzOg0KDQotICAgKipDbGFzZSAxOioqIFVuaW1vZGFsLCBjb252ZXhhLCBtdWx0aWRpbWVuc2lvbmFsLg0KLSAgICoqQ2xhc2UgMjoqKiBNdWx0aW1vZGFsLCBkb3MgZGltZW5zaW9uZXMgY29uIHVuIG7Dum1lcm8gcGVxdWXDsW8gZGUgZXh0cmVtb3MgbG9jYWxlcy4NCi0gICAqKkNsYXNlIDMqKjogTXVsdGltb2RhbCwgZG9zIGRpbWVuc2lvbmVzIGNvbiB1biBncmFuIG7Dum1lcm8gZGUgZXh0cmVtb3MgbG9jYWxlcy4NCi0gICAqKkNsYXNlIDQ6KiogTXVsdGltb2RhbCwgbXVsdGlkaW1lbnNpb25hbCwgY29uIHVuIG7Dum1lcm8gYW1wbGlvIGRlIGV4dHJlbW9zIGxvY2FsZXMuDQoNCkVuIGVsIGNhc28gZGUgbGFzIGZ1bmNpb25lcyBlbGVnaWRhcywgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBzZSBjbGFzaWZpY2Fyw61hIGNvbW8gQ2xhc2UgMyB5IGxhIGRlIFJhc3RyaWdpbiBjb21vIENsYXNlIDIuDQoNCkNvbW8gZWplbXBsbywgZW4gbGEgRmlndXJhIDEgc2UgcHJlc2VudGFuIGFsZ3VuYXMgZnVuY2lvbmVzIGRlIHBydWViYSBxdWUgbm8gc2UgZWxpZ2llcm9uIHBhcmEgZXN0ZSB0cmFiYWpvLCBwZXJvIHF1ZSBzb24gaWd1YWwgZGUgcmVsZXZhbnRlcywgaW1wb3J0YW50ZXMgeSBjb23Dum5tZW50ZSB1dGlsaXphZGFzIGVuIGxhIHByw6FjdGljYSAoTW9sZ2EsIDIwMDUpOg0KDQotICAgRnVuY2nDs24gZGUgRGUgSm9uZyAoQ2xhc2UgMSkuDQoNCi0gICBGdW5jacOzbiBkZSBHcmlld2FuZ2sgKENsYXNlIDIpLg0KDQotICAgRnVuY2nDs24gZGUgTGFuZ2VybWFubiAoQ2xhc2UgMykuDQoNCi0gICBGdW5jacOzbiBkZSBBY2tsZXkgKENsYXNlIDQpLg0KDQo8YSBuYW1lPSJpbzEuMS4yLiI+PC9hPg0KDQojIyMgMS4xLjIgRnVuY2nDs24gZGUgUm9zZW5icm9jaw0KDQpFcyB1bmEgZnVuY2nDs24gbm8gY29udmV4YSBpbnRyb2R1Y2lkYSBwb3IgUm9zZW5icm9jayBlbiAxOTYw4oCLIChXaWtpcGVkaWEsIHMuZi4sIFJvc2VuYnJvY2sgZnVuY3Rpb24pLiBTdSBwYWlzYWplIGZvcm1hIHVuIHZhbGxlIGN1cnZvIGVzdHJlY2hvIHF1ZSBkaWZpY3VsdGEgbGEgY29udmVyZ2VuY2lhIGhhY2lhIGVsIG3DrW5pbW8uDQoNCkRlZmluaWNpw7NuIGVuIG4gZGltZW5zaW9uZXM6DQoNCiRmKFgpID0gXHN1bV97aT0xfV57bi0xfTEwMChYX3tpKzF9LVhfaV4yKV4yICsgKDEtWF9pKV4yJCAoMSkNCg0KRGVmaW5pY2nDs24gZW4gMkQ6DQoNCiRmKHgseSk9IDEwMCh5LXheMileMiArICgxLXgpXjIkICgyKQ0KDQpEZWZpbmljacOzbiBlbiAzRDoNCg0KJGYoeCx5LHopPTEwMFsoeS14XjIpXjIrKHoteV4yKV4yXSArICgxLXgpXjIgKyAoMS15KV4yJCAoMykNCg0KQWxndW5hcyBjYXJhY3RlcsOtc3RpY2FzIHkgcHJvcGllZGFkZXMgaW1wb3J0YW50ZXPCoCBzb24gbGFzIHNpZ3VpZW50ZXM6DQoNCi0gICBFbCBtw61uaW1vIGdsb2JhbCBlc3TDoSBkYWRvIHBvciBsb3MgcHVudG9zIHF1ZSBjdW1wbGVuIGNvbiAkeF8xLC4uLix4X24gPTEkDQoNCi0gICBFbCBkb21pbmlvIGRlIGLDunNxdWVkYSBjb25zaXN0ZSBkZSB0b2RvIGVsIGVzcGFjaW8gcmVhbCwgZXMgZGVjaXIsIGRvbmRlIGNhZGEgcHVudG8gY3VtcGxlIGNvbsKgJC1caW5mdHkgXGxlcSBYX2kgXGxlcSBcaW5mdHksIDEgXGxlcSBpIFxsZXEgbiQuDQoNCi0gICBDb25vY2lkYSB0YW1iacOpbiBjb21vIGxhIGZ1bmNpw7NuIGJhbmFuYSBkZSBSb3NlbmJyb2NrLg0KDQotICAgVGllbmUgZm9ybWEgZGUgdmFsbGUsIGVsIGN1YWwgZXMgdHJpdmlhbCBlbmNvbnRyYXJsby4gU2luIGVtYmFyZ28sIGxhIGNvbnZlcmdlbmNpYSBhbCBtw61uaW1vIGdsb2JhbCBlcyBkaWbDrWNpbC4NCg0KRXN0YXMgc29uIGFsZ3VuYXMgaGlww7N0ZXNpcyB5IGV4cGVjdGF0aXZhcyBxdWUgc2UgdHV2aWVyb24gcGFyYSBlbCByZW5kaW1pZW50byBkZSBjYWRhIG3DqXRvZG8gaW1wbGVtZW50YWRvIGNvbiBlc3RhIGZ1bmNpw7NuOg0KDQotICAgKipNw6l0b2RvIGRlIGRlc2NlbnNvIGRlIGdyYWRpZW50ZToqKg0KDQogICAgLSAgIFNpIHNlIHViaWNhIGVsIHB1bnRvIGluaWNpYWwgc29icmUgbGFzIHJlY3RhcyB0YW5nZW50ZXMgY29uIG1heW9yIGdyYWRpZW50ZSBhIGxhIGZ1bmNpw7NuIGVudG9uY2VzIGVsIG3DqXRvZG8gbGxlZ2Fyw6EgbcOhcyByw6FwaWRvIGEgdW4gbcOtbmltby4NCiAgICAtICAgUG9yIGVsIGNvbnRyYXJpbywgc2kgbGEgcmVjdGEgdGFuZ2VudGUgdGllbmUgdW5hIGdyYWRpZW50ZSBtw6FzIGNlcmNhbmEgYSBjZXJvLCBlbCBtw6l0b2RvIGxsZWdhcsOhIG3DoXMgbGVudGFtZW50ZSwgZXMgZGVjaXIsIHJlcXVlcmlyw6EgZGUgbcOhcyBpdGVyYWNpb25lcyBwYXJhIGxsZWdhciBhbCBwdW50byBtw61uaW1vLg0KDQotICAgKipNw6l0b2RvIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvczoqKg0KDQogICAgLSAgIExvcyBjcml0ZXJpb3MgcGFyYSBzZWxlY2Npb25hciBsb3MgaW5kaXZpZHVvcyBhIHJlcHJvZHVjaXIgdmEgYSBzZXIgbXV5IGltcG9ydGFudGUgcGFyYSBlbCByZW5kaW1pZW50byBkZWwgbcOpdG9kby4NCg0KLSAgICoqTcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzOioqDQoNCiAgICAtICAgRXN0ZSBtw6l0b2RvIG5vIHZhIGEgdGVuZXIgbXVjaGFzIGRpZmljdWx0YWRlcyBwYXJhIGVuY29udHJhciBlbCBwdW50byDDs3B0aW1vIGVzIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2suDQogICAgLSAgIEVsIGNyaXRlcmlvIHBhcmEgcGFyYXIgbGFzIGl0ZXJhY2lvbmVzIG5vIHZhIGEgY2FtYmlhciBtdWNobyBsb3MgcmVzdWx0YWRvcyBlbiBlc3RlIGNhc28uDQoNCi0gICAqKk3DqXRvZG8gZGUgZXZvbHVjacOzbiBkaWZlcmVuY2lhbDoqKg0KDQogICAgLSAgIFNlIGNvbXBvcnRhIHNpbWlsYXIgYSBsb3MgbcOpdG9kb3MgZXZvbHV0aXZvcyBlbiAyIGRpbWVuc2lvbmVzLg0KDQpMYSBpbXBsZW1lbnRhY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAyLCAzIHkgTiBkaW1lbnNpb25lcyBzZSBtdWVzdHJhIGEgY29udGludWFjacOzbjoNCg0KYGBge3J9DQojIDIgRGltZW5zaW9uZXMNCmZfcm9zZW5icm9ja18yZCA8LSBmdW5jdGlvbih4LCB5KSB7ICAgDQogIGZfdmFsdWUgPC0gMTAwKih5LSh4XjIpKV4yICsgKCgxLXgpXjIpICAgDQogIHJldHVybihmX3ZhbHVlKSANCn0gIA0KDQojIDMgRGltZW5zaW9uZXMNCmZfcm9zZW5icm9ja18zZCA8LSBmdW5jdGlvbih4LCB5LCB6KSB7ICAgDQogIGZfdmFsdWUgPC0gMTAwKigoeS14XjIpXjIgKyAoei15XjIpXjIpICsgKDEteCleMiArICgxLXkpXjIgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfQ0KDQojIE4gRGltZW5zaW9uZXMNCmZfcm9zZW5icm9jayA8LSBmdW5jdGlvbih4KXsNCiAgeF8xIDwtIHRhaWwoeCwgLTEpDQogIHggPC0gaGVhZCh4LCAtMSkNCiAgeiA8LSBzdW0oKDEwMCooKHhfMS0oeF4yKSleMikpKygoMS14KV4yKSkNCiAgcmV0dXJuKHopDQp9DQpgYGANCg0KTGFzIGdyw6FmaWNhcyBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgeSAzIGRpbWVuc2lvbmVzIHNlIG11ZXN0cmFuIGEgY29udGludWFjacOzbjoNCg0KOjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KPGltZyBzcmM9ImltYWdlc1xncmFwaGljc1xyb3NlbmJyb2NrXzJkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgMkQiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpHcsOhZmljYSBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIDJEDQo6OjoNCjo6OjoNCg0KOjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KPGltZyBzcmM9ImltYWdlc1xncmFwaGljc1xyb3NlbmJyb2NrXzNkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgM0QiIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpHcsOhZmljYSBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIDNEDQo6OjoNCjo6OjoNCg0KPGEgbmFtZT0iaW8xLjEuMy4iPjwvYT4NCg0KIyMjIDEuMS4zIEZ1bmNpw7NuIGRlIFJhc3RyaWdpbg0KDQpMYSBmdW5jacOzbiBSYXN0cmlnaW4gKDE5NzQpIGVzIHVuYSBmdW5jacOzbiBubyBjb252ZXhhIHkgYWx0YW1lbnRlIG11bHRpbW9kYWwsIGNvbiBudW1lcm9zb3MgbcOtbmltb3MgbG9jYWxlcywgbG8gcXVlIGxhIGhhY2UgZGlmw61jaWwgZGUgb3B0aW1pemFy4oCLIChXaWtpcGVkaWEsIHMuZi4sIFJhc3RyaWdpbiBmdW5jdGlvbikuDQoNClByZXNlbnRhIG3Dumx0aXBsZXMgbcOtbmltb3MgbG9jYWxlcyBkaXNwdWVzdG9zIGRlIGZvcm1hIHJlZ3VsYXLigIssIGxvIHF1ZSBsbyBjb252aWVydGUgZW4gdW4gZGVzYWbDrW8gdMOtcGljbyBwYXJhIGFsZ29yaXRtb3MgZGUgb3B0aW1pemFjacOzbi4NCg0KRGVmaW5pY2nDs24gZW4gbiBkaW1lbnNpb25lczoNCg0KJGYoWCk9QW4gKyBcc3VtX3tpPTF9Xm5bWF9pXjIgLUFcY29zKDJccGkgWF9pKV0sIEE9MTAkICg0KQ0KDQpEZWZpbmljacOzbiBlbiAyRDoNCg0KJGYoeCx5KT14XjIreV4yK0FbMi1cY29zKDJccGkgeCkgLSBcY29zKDJccGkgeSldLCBBPTEwJCAoNSkNCg0KRGVmaW5pY2nDs24gZW4gM0Q6DQoNCiRmKHgseSk9eF4yK3leMit6XjIrQVszLVxjb3MoMlxwaSB4KSAtIFxjb3MoMlxwaSB5KS1cY29zKDJccGkgeildLCBBPTEwJCAoNikNCg0KQWxndW5hcyBjYXJhY3RlcsOtc3RpY2FzIHkgcHJvcGllZGFkZXMgaW1wb3J0YW50ZXMgc29uIGxhcyBzaWd1aWVudGVzOg0KDQotICAgRWwgbcOtbmltbyBnbG9iYWwgc2UgYWxjYW56YSBjdWFuZG8gZWwgdmVjdG9yIGVzIHVuIHZlY3RvciBudWxvLCBlcyBkZWNpciwgJFg9WzAsLi4uLDBdJCBwYXJhIG4gZGltZW5zaW9uZXMuDQoNCi0gICBFbCBkb21pbmlvIGRlIGLDunNxdWVkYSBjdW1wbGUgY29uICQtNS4xMiBcbGVxIFhfaSBcbGVxIDUuMTIkLg0KDQotICAgUGFydGljdWxhcm1lbnRlLCBoYWxsYXIgZWwgbcOtbmltbyBkZSBlc3RhIGZ1bmNpw7NuIGVzIHVuIHByb2JsZW1hIGRpZsOtY2lsIGRlYmlkbyBhIGxhIGxhcmdhIGNhbnRpZGFkIGRlIG3DrW5pbW9zIGxvY2FsZXMuDQoNCkVzdGFzIHNvbiBhbGd1bmFzIGhpcMOzdGVzaXMgeSBleHBlY3RhdGl2YXMgcXVlIHNlIHR1dmllcm9uIHBhcmEgZWwgcmVuZGltaWVudG8gZGUgY2FkYSBtw6l0b2RvIGltcGxlbWVudGFkbyBjb24gZXN0YSBmdW5jacOzbjoNCg0KLSAgICoqTcOpdG9kbyBkZSBkZXNjZW5zbyBkZSBncmFkaWVudGU6KioNCg0KICAgIC0gICBFbCDDqXhpdG8gZGVsIG3DqXRvZG8gZW4gYWxjYW56YXIgdW4gbcOtbmltbyBkZXBlbmRlcsOhIGVub3JtZW1lbnRlIGRlbCBwdW50byBpbmljaWFsIGVsZWdpZG8gZGViaWRvIGEgbG9zIG3Dumx0aXBsZXMgbcOtbmltb3MgbG9jYWxlcyBxdWUgdGllbmUgZXN0YSBmdW5jacOzbi4NCg0KLSAgICoqTcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3M6KioNCg0KICAgIC0gICBFcyBpbXBvcnRhbnRlIGhhY2VyIHVuYSBidWVuYSByZXByZXNlbnRhY2nDs24gZGUgbG9zIGluZGl2aWR1b3MsIHlhIHF1ZSBlbCByZW5kaW1pZW50byBwdWVkZSB2YXJpYXIgZGVwZW5kaWVuZG8gZGUgbGEgc2VsZWNjacOzbi4NCiAgICAtICAgTGEgcG9ibGFjacOzbiBpbmljaWFsIGRlYmUgc2VyIHJlcHJlc2VudGF0aXZhLCBkaWZlcmVudGVzIGVudHJlIGVsbG9zIHkgcXVlIG5vIHNlYW4gZGVtYXNpYWRvcy4gUGFyYSBlc3RhIGZ1bmNpw7NuIGVuIHBhcnRpY3VsYXIgZW5jb250cmFyIGxhIHNvbHVjacOzbiDDs3B0aW1hIHZhIGEgZGVwZW5kZXIgbXVjaG8gZGUgbGEgcHJvYmFiaWxpZGFkIGRlIG11dGFjacOzbg0KDQotICAgKipNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXM6KioNCg0KICAgIC0gICBMYSB1YmljYWNpw7NuIGRlIGxhIG51YmUgZGUgcGFydMOtY3VsYXMgdmEgYSBhZmVjdGFyIGVsIHJlbmRpbWllbnRvIGVuIGVzdGEgZnVuY2nDs24sIHlhIHF1ZSBlbCBhbGdvcml0bW8gcHVlZGUgcXVlZGFyc2UgZXN0YW5jYWRvIGVuIHVuIG3DrW5pbW8gbG9jYWwgc2kgbGEgdWJpY2FjacOzbiBubyBlcyBsYSBtZWpvci4NCiAgICAtICAgRWwgY3JpdGVyaW8gcGFyYSBkZXRlbmVyIGVsIGFsZ29yaXRtbyBkZWJlIGVzdGFyIGJpZW4gYWp1c3RhZG8sIHBhcmEgZXZpdGFyIGVzdGFuY2FtaWVudG9zLg0KDQotICAgKipNw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWw6KioNCg0KICAgIC0gICBFcyBtw6FzIGVmaWNpZW50ZSBxdWUgbG9zIG90cm9zIG3DqXRvZG9zIGV2b2x1dGl2b3MgeWEgcXVlIHN1IGZ1ZXJ0ZSBzb24gbGFzIG3Dumx0aXBsZXMgZGltZW5zaW9uZXMuDQoNCkxhIGltcGxlbWVudGFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiwgMyB5IE4gZGltZW5zaW9uZXMgc2UgbXVlc3RyYSBhIGNvbnRpbnVhY2nDs246DQoNCmBgYHtyfQ0KIyAyIERpbWVuc2lvbmVzIA0KZl9yYXN0cmlnaW5fMmQgPC0gZnVuY3Rpb24oeCwgeSkgew0KICBBID0gMTAgICANCiAgZl92YWx1ZSA8LSB4XjIgKyB5XjIgKyBBKigyIC0gY29zKDIqcGkqeCkgLSBjb3MoMipwaSp5KSkgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfSAgDQoNCiMgMyBEaW1lbnNpb25lcyANCmZfcmFzdHJpZ2luXzNkIDwtIGZ1bmN0aW9uKHgsIHksIHopIHsgICANCiAgQSA9IDEwICAgDQogIGZfdmFsdWUgPC0geF4yICsgeV4yICsgel4yICsgQSooMyAtIGNvcygyKnBpKngpIC0gY29zKDIqcGkqeSkgLSBjb3MoMipwaSp6KSkgICANCiAgcmV0dXJuKGZfdmFsdWUpIA0KfQ0KDQojIE4gRGltZW5zaW9uZXMNCmZfcmFzdHJpZ2luIDwtZnVuY3Rpb24oeCl7DQogIEEgPC0gMTANCiAgbiA8LSBsZW5ndGgoeCkNCiAgeiA8LSAoQSpuKSArIHN1bSh4XjIgLSBBKmNvcygyKnBpKngpKQ0KICByZXR1cm4oeikNCn0NCmBgYA0KDQpMYXMgZ3LDoWZpY2FzIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIHkgMyBkaW1lbnNpb25lcyBzZSBtdWVzdHJhbiBhIGNvbnRpbnVhY2nDs246DQoNCjo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJpbWFnZXNcZ3JhcGhpY3NccmFzdHJpZ2luXzJkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiAyRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiAyRA0KOjo6DQo6Ojo6DQoNCjo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJpbWFnZXNcZ3JhcGhpY3NccmFzdHJpZ2luXzNkX2dyYWZpY2EucG5nIiBhbHQ9Ikdyw6FmaWNhIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiAzRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkdyw6FmaWNhcyBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gM0QNCjo6Og0KOjo6Og0KDQo8YSBuYW1lPSJpbzEuMi4iPjwvYT4NCg0KIyMgMS4yIE3DqXRvZG8gZGUgZGVzY2Vuc28gZGUgZ3JhZGllbnRlDQoNCkVsIG3DqXRvZG8gZGUgb3B0aW1pemFjacOzbiBwb3IgZGVzY2Vuc28gZGUgZ3JhZGllbnRlIGVzIHVuYSB0w6ljbmljYSBpdGVyYXRpdmEgdXRpbGl6YWRhIHBhcmEgZW5jb250cmFyIGVsIG3DrW5pbW8gZGUgdW5hIGZ1bmNpw7NuLiBDb25zaXN0ZSBlbiBhY3R1YWxpemFyIHN1Y2VzaXZhbWVudGUgbG9zIHZhbG9yZXMgZGUgbGFzIHZhcmlhYmxlcyBlbiBsYSBkaXJlY2Npw7NuIG9wdWVzdGEgYWwgZ3JhZGllbnRlIGRlIGxhIGZ1bmNpw7NuLCBjb24gZWwgb2JqZXRpdm8gZGUgcmVkdWNpciBzdSB2YWxvciBlbiBjYWRhIHBhc28uDQoNCkVuIG51ZXN0cm8gY2Fzbywgc2UgdXRpbGl6YXJvbiBsYXMgc2lndWllbnRlcyB2YXJpYWJsZXMgcGFyYSBpbXBsZW1lbnRhciBlbCBtw6l0b2RvOiAqKljigoAqKiwgcXVlIHJlcHJlc2VudGEgbGEgY29uZGljacOzbiBpbmljaWFsIGRlbCBhbGdvcml0bW87ICoqSCoqLCBxdWUgZGVmaW5lIGVsIHRhbWHDsW8gZGUgbGEgdmVudGFuYSBwYXJhIGVsIGPDoWxjdWxvIGRlIGxhIGRlcml2YWRhIG51bcOpcmljYTsgeSAqKkVUQSoqLCBxdWUgY29ycmVzcG9uZGUgYSBsYSB0YXNhIGRlIGFwcmVuZGl6YWplLCBlcyBkZWNpciwgZWwgdGFtYcOxbyBkZWwgcGFzbyBxdWUgc2UgZGEgZW4gY2FkYSBpdGVyYWNpw7NuIGhhY2lhIGVsIG3DrW5pbW8uDQoNCjxhIG5hbWU9ImlvMS4yLjEuIj48L2E+DQoNCiMjIyAxLjIuMSBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBkZXNjZW5zbyBkZSBncmFkaWVudGUNCg0KYGBge3J9DQojIEltcGxlbWVudGFjacOzbiBjb21wbGV0YSBkZSBvcHRpbWl6YWRvciBtdWx0aXZhcmlhZG8gcG9yIGRlc2NlbnNvIGRlIGdyYWRpZW50ZQ0Kb3B0aW1pemFkb3JfbXVsdF9udW1kZXYgPC0gZnVuY3Rpb24oeDAsZnVuLG1heF9ldmFsPTEwMCxoPTAuMDEsZXRhPTAuMDEpew0KICB4IDwtIG1hdHJpeChOQSxuY29sID1sZW5ndGgoeDApLCBucm93ID0gbWF4X2V2YWwpDQogIHhbMSxdIDwtIHgwDQogIGZvciAoaSBpbiAyOm1heF9ldmFsKXsNCiAgICBudW1fZ3JhZF9mdW4gPC0gbnVtX2dyYWQoeFtpLTEsXSxmdW4saCkNCiAgICBIIDwtIG1hdHJpel9oZXNzaWFuYSh4W2ktMSxdLGZ1bixoKQ0KICAgIGNhbWJpbyA8LSAtIGV0YSpzb2x2ZShIKSUqJW51bV9ncmFkX2Z1bg0KICAgIHhbaSxdIDwtIHhbaS0xLF0gKyBjYW1iaW8NCiAgICBjYW1iaW9fb3B0IDwtIHNxcnQoc3VtKCh4W2ktMSxdLXhbaSxdKV4yKSkNCiAgICBpZiAoY2FtYmlvX29wdDwwLjAwMDAxKXsNCiAgICAgIGJyZWFrDQogICAgfQ0KICB9DQogIHJldHVybih4WzE6aSxdKQ0KfQ0KYGBgDQoNCjxhIG5hbWU9ImlvMS4yLjIuIj48L2E+DQoNCiMjIyAxLjIuMiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMiBkaW1lbnNpb25lcw0KDQpgYGB7cn0NCnNvbF9yb3NlbjJkIDwtIG9wdGltaXphZG9yX211bHRfbnVtZGV2KGZfcm9zZW5icm9jaywgeDA9YygtNCwtNCksIGg9MC4wMDUsIGV0YT0wLjUpDQpgYGANCg0KTGEgc2lndWllbnRlIGFuaW1hY2nDs24gbXVlc3RyYSBlbCBkZXNlbXBlw7FvIGRlIGxhIG9wdGltaXphY2nDs24gYSB0cmF2ZXMgZGUgc3UgdHJheWVjdG9yaWE6DQoNCjo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJQYXJ0ZSAxXERlc2NlbnNvIGRlIGdyYWRpZW50ZVxyb3NlbmJyb2NrX29wdF9ncmFkXzJkLmdpZiIgYWx0PSJBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAyRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDJEDQo6OjoNCjo6OjoNCg0KPGEgbmFtZT0iaW8xLjIuMy4iPjwvYT4NCg0KIyMjIDEuMi4zIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzDQoNCmBgYHtyfQ0Kc29sX3Jvc2VuM2QgPC0gb3B0aW1pemFkb3JfbXVsdF9udW1kZXYoZl9yb3NlbmJyb2NrLCB4MD1jKC00LC00LC00KSwgaD0wLjAwNSwgZXRhPTAuNSkNCmBgYA0KDQpFbiBsYSBzaWd1aWVudGUgdGFibGEgZGUgbXVlc3RyYW4gZWwgY29tcG9ydGFtaWVudG8gY2FkYSAxMCBpdGVyYWNpb25lczoNCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRGVzY2Vuc28gZGUgZ3JhZGllbnRlL3Jvc2VuYnJvY2tfaXRlcl9ncmFkLmNzdiIpDQpgYGANCg0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCAgICB8IEl0ZXJhY2lvbiB8IFgxICAgICAgICAgfCBYMiAgICAgICAgICAgfCBYMyAgICAgICAgICAgfCBmX3ggICAgICAgICAgfA0KfCAgICB8ICAgICAgICAgICB8ICAgICAgICAgICAgfCAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfA0KfCAgICB8IFw8aW50XD4gICB8IFw8ZGJsXD4gICAgfCBcPGRibFw+ICAgICAgfCBcPGRibFw+ICAgICAgfCBcPGRibFw+ICAgICAgfA0KKzo9PT0rPT09PT09PT09PTorPT09PT09PT09PT06Kz09PT09PT09PT09PT06Kz09PT09PT09PT09PT06Kz09PT09PT09PT09PT06Kw0KfCAxMCB8IDEwICAgICAgICB8IC0wLjQ3NDY1ODggfCAtMC45NTgwODkwMDMgfCAwLjU1MTY1NTk5MCAgfCAxLjU5NDY1OWUrMDIgfA0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCAyMCB8IDIwICAgICAgICB8IDAuMTU3MzE0MiAgfCAwLjAwODEwMTYzOSAgfCAtMC4wMDIxNTg4NTggfCAxLjcyMjE4NmUrMDAgfA0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCAzMCB8IDMwICAgICAgICB8IDAuODYyMjM4MyAgfCAwLjczOTk3ODEyOCAgfCAwLjUzOTQzNjMwNyAgfCA5LjQ0MTAyN2UtMDIgfA0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCA0MCB8IDQwICAgICAgICB8IDAuOTk1MTgzNSAgfCAwLjk5MDM0ODMzNCAgfCAwLjk4MDYxNjczOSAgfCAxLjE5NTI0MWUtMDQgfA0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCA1MCB8IDUwICAgICAgICB8IDAuOTk3MDA0MiAgfCAwLjk5NDAyNzI1NiAgfCAwLjk4ODA5MDAwMiAgfCA0LjQ2NTg1MWUtMDUgfA0KKy0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KDQoqKlRhYmxhIDEuKiogVGFibGEgZGUgZWplY3VjacOzbiBkZSBvcHRpbWl6YWNpw7NuIGRlIFJvc2VuYnJvY2sgM0QgdXRpbGl6YW5kbyBEZXNjZW5zbyBkZSBHcmFkaWVudGUNCg0KPGEgbmFtZT0iaW8xLjIuNC4iPjwvYT4NCg0KIyMjIDEuMi40IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXMNCg0KYGBge3J9DQpzb2xfcmFzMmQgPC0gb3B0aW1pemFkb3JfbXVsdF9udW1kZXYoZl9yYXN0cmlnaW4sIHgwPWMoNC41LDQuNSksIGg9MC4wMDUsIGV0YT0yKQ0KYGBgDQoNCkxhIHNpZ3VpZW50ZSBhbmltYWNpw7NuIG11ZXN0cmEgZWwgZGVzZW1wZcOxbyBkZSBsYSBvcHRpbWl6YWNpw7NuIGEgdHJhdmVzIGRlIHN1IHRyYXllY3RvcmlhOg0KDQo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0iUGFydGUgMVxEZXNjZW5zbyBkZSBncmFkaWVudGVccmFzdHJpZ2luX29wdF9ncmFkXzJkLmdpZiIgYWx0PSJBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDJEIiBzdHlsZT0id2lkdGg6MzUwcHg7IG1heC13aWR0aDo5MCU7IGRpc3BsYXk6YmxvY2s7IG1hcmdpbjphdXRvOyIvPg0KDQo6Ojoge3N0eWxlPSJmb250LXdlaWdodDpib2xkOyBtYXJnaW4tdG9wOjhweDsgZm9udC1zaXplOjEuMDVlbTsifQ0KQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJhc3RyaWdpbiAyRA0KOjo6DQo6Ojo6DQoNCjxhIG5hbWU9ImlvMS4yLjUuIj48L2E+DQoNCiMjIyAxLjIuNSBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzDQoNCmBgYHtyfQ0Kc29sX3JhczNkIDwtIG9wdGltaXphZG9yX211bHRfbnVtZGV2KGZfcmFzdHJpZ2luLCB4MD1jKC00LC00LC00KSwgIGg9MC4wMDUsIGV0YT0yKQ0KYGBgDQoNCkVuIGxhIHNpZ3VpZW50ZSB0YWJsYSBkZSBtdWVzdHJhbiBlbCBjb21wb3J0YW1pZW50byBjYWRhIDEwIGl0ZXJhY2lvbmVzOg0KDQpgYGB7cn0NCnNob3dfdGFibGUoIi4vUGFydGUgMS9EZXNjZW5zbyBkZSBncmFkaWVudGUvcmFzdHJpZ2luX2l0ZXJfZ3JhZC5jc3YiKQ0KYGBgDQoNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tKw0KfCAgICAgfCBJdGVyYWNpb24gfCBYMSAgICAgICAgfCBYMiAgICAgICAgfCBYMyAgICAgICAgfCBmX3ggICAgICB8DQp8ICAgICB8ICAgICAgICAgICB8ICAgICAgICAgICB8ICAgICAgICAgICB8ICAgICAgICAgICB8ICAgICAgICAgIHwNCnwgICAgIHwgXDxpbnRcPiAgIHwgXDxkYmxcPiAgIHwgXDxkYmxcPiAgIHwgXDxkYmxcPiAgIHwgXDxkYmxcPiAgfA0KKz09PT09Kz09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PTorDQp8IDEwICB8IDEwICAgICAgICB8IC0zLjk1NzY0NiB8IC0zLjk1NzY0NiB8IC0zLjk1NzY0NiB8IDQ4LjA0NDkyIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tKw0KfCAyMCAgfCAyMCAgICAgICAgfCAtMy45NTQwMjggfCAtMy45NTQwMjggfCAtMy45NTQwMjggfCA0OC4xNDU4NyB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSsNCnwgMzAgIHwgMzAgICAgICAgIHwgLTMuOTQ3ODM2IHwgLTMuOTQ3ODM2IHwgLTMuOTQ3ODM2IHwgNDguMzUzMjEgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rDQp8IDQwICB8IDQwICAgICAgICB8IC0zLjkzMzE5NCB8IC0zLjkzMzE5NCB8IC0zLjkzMzE5NCB8IDQ5LjAxNDM5IHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tKw0KfCA1MCAgfCA1MCAgICAgICAgfCAtMy4zOTk2NjIgfCAtMy4zOTk2NjIgfCAtMy4zOTk2NjIgfCA4OC45MDYwOSB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSsNCnwgNjAgIHwgNjAgICAgICAgIHwgLTQuOTg0MjIwIHwgLTQuOTg0MjIwIHwgLTQuOTg0OTcxIHwgNzQuNjc3NjEgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rDQp8IDcwICB8IDcwICAgICAgICB8IC00Ljk4NDQ4NyB8IC00Ljk4NDQ4NyB8IC00Ljk4NTMwMSB8IDc0LjY4MTAwIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tKw0KfCA4MCAgfCA4MCAgICAgICAgfCAtNC45ODQ3NzUgfCAtNC45ODQ3NzUgfCAtNC45ODU2NjMgfCA3NC42ODQ3OSB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSsNCnwgOTAgIHwgOTAgICAgICAgIHwgLTQuOTg1MDg3IHwgLTQuOTg1MDg3IHwgLTQuOTg2MDYyIHwgNzQuNjg5MDYgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rDQp8IDEwMCB8IDEwMCAgICAgICB8IC00Ljk4NTQyOSB8IC00Ljk4NTQyOSB8IC00Ljk4NjUwNSB8IDc0LjY5MzkyIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tKw0KDQoqKlRhYmxhIDIuKiogVGFibGEgZGUgZWplY3VjacOzbiBkZSBvcHRpbWl6YWNpw7NuIGRlIFJhc3RyaWdpbiAzRCB1dGlsaXphbmRvIERlc2NlbnNvIGRlIEdyYWRpZW50ZQ0KDQo8YSBuYW1lPSJpbzEuMi42LiI+PC9hPg0KDQojIyMgMS4yLjYgQ29uY2x1c2lvbmVzIG3DqXRvZG8gZGUgZGVzZW5zbyBkZWwgZ3JhZGllbnRlDQoNCkVsIG3DqXRvZG8gZGUgb3B0aW1pemFjacOzbiBwb3IgZGVzY2Vuc28gZGUgZ3JhZGllbnRlIHNlIGNhcmFjdGVyaXphIHBvciBzdSBzaW1wbGljaWRhZCB5IGZhY2lsaWRhZCBkZSBpbXBsZW1lbnRhY2nDs24sIGxvIHF1ZSBsbyBjb252aWVydGUgZW4gdW5hIGhlcnJhbWllbnRhIMO6dGlsIHBhcmEgZnVuY2lvbmVzIGNvbiBzdXBlcmZpY2llcyBzdWF2ZXMgeSByZWxhdGl2YW1lbnRlIHNpbXBsZXMuIFNpbiBlbWJhcmdvLCBhbCBhcGxpY2Fyc2UgYSBmdW5jaW9uZXMgYWx0YW1lbnRlIG5vIGNvbnZleGFzIGNvbW8gbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luLCBlc3RlIG3DqXRvZG8gcHJlc2VudGEgbGltaXRhY2lvbmVzIHNpZ25pZmljYXRpdmFzLCB5YSBxdWUgdGllbmRlIGEgcXVlZGFyIGF0cmFwYWRvIGVuIG3DrW5pbW9zIGxvY2FsZXMsIGRpZmljdWx0YW5kbyBsYSBjb252ZXJnZW5jaWEgaGFjaWEgdW5hIHNvbHVjacOzbiBnbG9iYWwgw7NwdGltYS4NCg0KPGEgbmFtZT0iaW8xLjMuIj48L2E+DQoNCiMjIDEuMyBNw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwNCg0KTGEgZXZvbHVjacOzbiBkaWZlcmVuY2lhbCBlcyB1biBhbGdvcml0bW8gZGUgb3B0aW1pemFjacOzbiBpbnNwaXJhZG8gZW4gbGEgZXZvbHVjacOzbiBiaW9sw7NnaWNhLiBGdW5jaW9uYSBtYW50ZW5pZW5kbyB1bmEgcG9ibGFjacOzbiBkZSBzb2x1Y2lvbmVzLCB5IG1lam9yw6FuZG9sYXMgZ2VuZXJhY2nDs24gdHJhcyBnZW5lcmFjacOzbiBtZWRpYW50ZSBvcGVyYWNpb25lcyBkZSBtdXRhY2nDs24sIHJlY29tYmluYWNpw7NuIHkgc2VsZWNjacOzbi4NCg0KLSAgICoqTXV0YWNpw7NuKio6IHNlIGNvbWJpbmFuIDMgaW5kaXZpZHVvcyBkaXN0aW50b3MgZGUgbGEgcG9ibGFjacOzbiBwYXJhIGNyZWFyIHVuYSB2YXJpYW50ZS4NCi0gICAqKlJlY29tYmluYWNpw7NuKio6IHNlIG1lemNsYSBlc2EgdmFyaWFudGUgY29uIGVsIGluZGl2aWR1byBhY3R1YWwuDQotICAgKipTZWxlY2Npw7NuKio6IHNlIGVzY29nZSBlbCBtZWpvciBlbnRyZSBlbCBvcmlnaW5hbCB5IGVsIG51ZXZvLg0KDQpFc3RlIHByb2Nlc28gc2UgcmVwaXRlIHZhcmlhcyB2ZWNlcyBoYXN0YSBlbmNvbnRyYXIgdW5hIHNvbHVjacOzbiDDs3B0aW1hLg0KDQpMYXMgdmFyaWFibGVzIHNvbjogKipkaW0qKiwgcXVlIHJlcHJlc2VudGEgbGEgY2FudGlkYWQgZGUgZGltZW5zaW9uZXMgbyB2YXJpYWJsZXMgZGVsIHByb2JsZW1hOyAqKk5QKiosIHF1ZSBpbmRpY2EgZWwgdGFtYcOxbyBkZSBsYSBwb2JsYWNpw7NuIG8gbsO6bWVybyBkZSBzb2x1Y2lvbmVzIGVuIGNhZGEgZ2VuZXJhY2nDs247ICoqRioqLCBxdWUgZXMgZWwgZmFjdG9yIGRlIG11dGFjacOzbiB5IGRldGVybWluYSBsYSBpbnRlbnNpZGFkIGRlIGxhIHBlcnR1cmJhY2nDs24gYXBsaWNhZGEgYSBsYXMgc29sdWNpb25lczsgKipDUioqLCBxdWUgY29ycmVzcG9uZGUgYSBsYSB0YXNhIGRlIHJlY29tYmluYWNpw7NuIHkgY29udHJvbGEgbGEgcHJvYmFiaWxpZGFkIGRlIGludGVyY2FtYmlvIGRlIGNvbXBvbmVudGVzIGVudHJlIHZlY3RvcmVzOyAqKmdlbnMqKiwgcXVlIGRlZmluZSBlbCBuw7ptZXJvIHRvdGFsIGRlIGdlbmVyYWNpb25lcyBvIGl0ZXJhY2lvbmVzIGRlbCBhbGdvcml0bW87IHkgKipib3VuZHMqKiwgcXVlIGVzdGFibGVjZSBsb3MgbMOtbWl0ZXMgaW5mZXJpb3IgeSBzdXBlcmlvciBkZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEgcGFyYSBjYWRhIGRpbWVuc2nDs24uDQoNCjxhIG5hbWU9ImlvMS4zLjEuIj48L2E+DQoNCiMjIyAxLjMuMSBJbXBsZW1lbnRhY2nDs24gZW4gUiBkZSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsDQoNCmBgYHtyfQ0KZXZvbHVjaW9uX2RpZmVyZW5jaWFsIDwtIGZ1bmN0aW9uKGZ1bl9vYmosIGRpbSA9IDIsIE5QID0gMzAsIEYgPSAwLjgsIENSID0gMC45LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbnMgPSAxMDAsIGJvdW5kcyA9IGMoLTUsIDUpKSB7DQoNCiAgIyBJbmljaWFsaXphciBwb2JsYWNpw7NuDQogIHBvYmxhY2lvbiA8LSBtYXRyaXgocnVuaWYoTlAgKiBkaW0sIGJvdW5kc1sxXSwgYm91bmRzWzJdKSwgbmNvbCA9IGRpbSkNCiAgZml0bmVzcyA8LSBhcHBseShwb2JsYWNpb24sIDEsIGZ1bl9vYmopDQoNCiAgaGlzdG9yaWFsIDwtIG51bWVyaWMoZ2VucykNCiAgbWVqb3JlcyA8LSBtYXRyaXgoTkEsIGdlbnMsIGRpbSkNCg0KICBmb3IgKGdlbiBpbiAxOmdlbnMpIHsNCiAgICBmb3IgKGkgaW4gMTpOUCkgew0KICAgICAgIyBTZWxlY2Npb25hciAzIMOtbmRpY2VzIGRpc3RpbnRvcw0KICAgICAgaW5kaWNlcyA8LSBzYW1wbGUoc2V0ZGlmZigxOk5QLCBpKSwgMykNCiAgICAgIHgxIDwtIHBvYmxhY2lvbltpbmRpY2VzWzFdLCBdDQogICAgICB4MiA8LSBwb2JsYWNpb25baW5kaWNlc1syXSwgXQ0KICAgICAgeDMgPC0gcG9ibGFjaW9uW2luZGljZXNbM10sIF0NCg0KICAgICAgIyBNdXRhY2nDs24NCiAgICAgIG11dGFkbyA8LSB4MSArIEYgKiAoeDIgLSB4MykNCg0KICAgICAgIyBSZWNvbWJpbmFyDQogICAgICB0cmlhbCA8LSBwb2JsYWNpb25baSwgXQ0KICAgICAganJhbmQgPC0gc2FtcGxlKDE6ZGltLCAxKQ0KICAgICAgZm9yIChqIGluIDE6ZGltKSB7DQogICAgICAgIGlmIChydW5pZigxKSA8IENSIHx8IGogPT0ganJhbmQpIHsNCiAgICAgICAgICB0cmlhbFtqXSA8LSBtdXRhZG9bal0NCiAgICAgICAgfQ0KICAgICAgfQ0KDQogICAgICAjIFNlbGVjY2nDs24NCiAgICAgIGlmIChmdW5fb2JqKHRyaWFsKSA8IGZpdG5lc3NbaV0pIHsNCiAgICAgICAgcG9ibGFjaW9uW2ksIF0gPC0gdHJpYWwNCiAgICAgICAgZml0bmVzc1tpXSA8LSBmdW5fb2JqKHRyaWFsKQ0KICAgICAgfQ0KICAgIH0NCg0KICAgICMgR3VhcmRhciBtZWpvciByZXN1bHRhZG8NCiAgICBiZXN0X2lkeCA8LSB3aGljaC5taW4oZml0bmVzcykNCiAgICBoaXN0b3JpYWxbZ2VuXSA8LSBmaXRuZXNzW2Jlc3RfaWR4XQ0KICAgIG1lam9yZXNbZ2VuLCBdIDwtIHBvYmxhY2lvbltiZXN0X2lkeCwgXQ0KICB9DQoNCiAgbGlzdChtZWpvciA9IHBvYmxhY2lvblt3aGljaC5taW4oZml0bmVzcyksIF0sDQogICAgICAgdmFsb3IgPSBtaW4oZml0bmVzcyksDQogICAgICAgaGlzdG9yaWFsID0gaGlzdG9yaWFsLA0KICAgICAgIHRyYXllY3RvcmlhID0gbWVqb3JlcykNCn0NCmBgYA0KDQo8YSBuYW1lPSJpbzEuMy4yLiI+PC9hPg0KDQojIyMgMS4zLjIgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXMNCg0KRW4gZXN0ZSBncsOhZmljbyBzZSBtdWVzdHJhbiBsYXMgY3VydmFzIGRlIG5pdmVsIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gZG9zIGRpbWVuc2lvbmVzLiBFc3RhcyBjdXJ2YXMgcmVwcmVzZW50YW4gbMOtbmVhcyBkb25kZSBsYSBmdW5jacOzbiB0aWVuZSBpZ3VhbCB2YWxvciwgeSBlbCB2YWxsZSBjdXJ2YWRvIGFsIGNlbnRybyBlcyBkb25kZSBlc3TDoSBlbCBtw61uaW1vIGdsb2JhbCAoZW4gZWwgcHVudG8gKDEsMSkoMSwxKSkuDQoNCkxhIGzDrW5lYSByb2phIHJlcHJlc2VudGEgbGEgdHJheWVjdG9yaWEgcXVlIHNpZ3Vpw7MgZWwgYWxnb3JpdG1vIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwgZHVyYW50ZSBsYXMgaXRlcmFjaW9uZXMuIFNlIHB1ZWRlIG9ic2VydmFyIGPDs21vIGVsIGVuamFtYnJlIGRlIHNvbHVjaW9uZXMgc2UgZnVlIGFjZXJjYW5kbyBwcm9ncmVzaXZhbWVudGUgaGFjaWEgZWwgbcOtbmltbywgbWVqb3JhbmRvIHN1IHBvc2ljacOzbiBlbiBjYWRhIGdlbmVyYWNpw7NuLg0KDQo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0iUGFydGUgMVxFdm9sdWNpb25fRGlmZXJlbmNpYWxccm9zZW5icm9ja19vcHRfZXZkXzJkLmdpZiIgYWx0PSJBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAyRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDJEDQo6OjoNCjo6OjoNCg0KRWwgcmVzdWx0YWRvIGZpbmFsIG9idGVuaWRvIGZ1ZTogWzFdIDEuMDAwMDAwIDEuMDAwMDAxIFZhbG9yIG3DrW5pbW8gZW5jb250cmFkbzogMS45MWUtMTINCg0KPGEgbmFtZT0iaW8xLjMuMy4iPjwvYT4NCg0KIyMjIDEuMy4zIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUm9zZW5icm9jayBlbiAzIGRpbWVuc2lvbmVzDQoNCkVuIGVzdGEgcGFydGUgZGVsIGluZm9ybWUgc2UgbXVlc3RyYW4gbG9zIHJlc3VsdGFkb3MgbnVtw6lyaWNvcyBwYXJhIGxhIG9wdGltaXphY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBlbiAzRC4gRGFkbyBxdWUgbm8gc2UgcHVlZGUgdmlzdWFsaXphciBmw6FjaWxtZW50ZSBlbiB1bmEgZ3LDoWZpY2EgM0QgZGUgdHJheWVjdG9yaWEsIHNlIHJlcG9ydGFuIGxhcyBtZWpvcmVzIHBvc2ljaW9uZXMgeSB2YWxvcmVzIG9idGVuaWRvLg0KDQpgYGB7cn0NCnNob3dfdGFibGUoIi4vUGFydGUgMS9Fdm9sdWNpb25fRGlmZXJlbmNpYWwvcm9zZW5icm9ja19pdGVyX2V2ZC5jc3YiKQ0KYGBgDQoNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rDQp8ICAgICB8IEl0ZXJhY2lvbiB8IFgxICAgICAgICAgfCBYMiAgICAgICAgfCBYMyAgICAgICAgfCBmX3ggICAgICAgICAgfA0KfCAgICAgfCAgICAgICAgICAgfCAgICAgICAgICAgIHwgICAgICAgICAgIHwgICAgICAgICAgIHwgICAgICAgICAgICAgIHwNCnwgICAgIHwgXDxpbnRcPiAgIHwgXDxkYmxcPiAgICB8IFw8ZGJsXD4gICB8IFw8ZGJsXD4gICB8IFw8ZGJsXD4gICAgICB8DQorPT09PT0rPT09PT09PT09PTorPT09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PT09PT06Kw0KfCAxMCAgfCAxMCAgICAgICAgfCAtMC41ODUxNzY4IHwgMC4xMTMwNjg5IHwgMC44NjQ5NDM3IHwgOC4xMTc3NjllKzAxIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rDQp8IDIwICB8IDIwICAgICAgICB8IDAuODgwNDU4MiAgfCAwLjUyMDk4MzEgfCAwLjQ3ODA0MDcgfCAxLjA5NzU3OGUrMDEgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSsNCnwgMzAgIHwgMzAgICAgICAgIHwgMC42OTA5NjA2ICB8IDAuNDYyNjYxMSB8IDAuMzU3NDMyMCB8IDIuNDYxNzI4ZSswMCB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCA0MCAgfCA0MCAgICAgICAgfCAwLjg1Mzg4NjIgIHwgMC42NzkxMjA4IHwgMC4zNTM5MzUxIHwgMS41MjUwMDZlKzAwIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rDQp8IDUwICB8IDUwICAgICAgICB8IDAuNjYxODkyNyAgfCAwLjQ5NjM5NDUgfCAwLjIyNjkxNjQgfCA3LjQ1NzI3NmUtMDEgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSsNCnwgNjAgIHwgNjAgICAgICAgIHwgMC44NzUyOTMyICB8IDAuNzU4MzI0NSB8IDAuNTk3Njc1MSB8IDEuMzEyMjYxZS0wMSB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCA3MCAgfCA3MCAgICAgICAgfCAwLjk2NzMzMTIgIHwgMC45MzI3Mzg1IHwgMC44Nzc5NzM0IHwgMS4yODQxOThlLTAyIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rDQp8IDgwICB8IDgwICAgICAgICB8IDEuMDAyMzc1NiAgfCAxLjAwNjYxMTEgfCAxLjAxMzY3MjQgfCA0LjA5Njk0NmUtMDQgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSsNCnwgOTAgIHwgOTAgICAgICAgIHwgMS4wMDIzNzU2ICB8IDEuMDA2NjExMSB8IDEuMDEzNjcyNCB8IDQuMDk2OTQ2ZS0wNCB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKw0KfCAxMDAgfCAxMDAgICAgICAgfCAwLjk5OTgyNjAgIHwgMC45OTk4MDE0IHwgMC45OTk2MjY1IHwgMi4zNTc5MjhlLTA2IHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rDQoNCioqVGFibGEgMy4qKiBUYWJsYSBkZSBlamVjdWNpw7NuIGRlIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAzRCB1dGlsaXphbmRvIEV2b2x1Y2nDs24gRGlmZXJlbmNpYWwNCg0KPGEgbmFtZT0iaW8xLjMuNC4iPjwvYT4NCg0KIyMjIDEuMy40IE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDIgZGltZW5zaW9uZXMNCg0KQXF1w60gc2UgZ3JhZmljYW4gbGFzIGN1cnZhcyBkZSBuaXZlbCBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4sIHF1ZSBlcyBtdWx0aW1vZGFsLCBlcyBkZWNpciwgdGllbmUgbXVjaG9zIG3DrW5pbW9zIGxvY2FsZXMgKHBhdHLDs24gb25kdWxhZG8pLiBMYSBiw7pzcXVlZGEgZXMgbXVjaG8gbcOhcyBjb21wbGVqYSBxdWUgZW4gUm9zZW5icm9jay4NCg0KTGEgbMOtbmVhIGF6dWwgbXVlc3RyYSBjw7NtbyBsYSBldm9sdWNpw7NuIGRpZmVyZW5jaWFsIHNlIG11ZXZlIHBvciBlbCBlc3BhY2lvIGRlIGLDunNxdWVkYSB5IGxvZ3JhIGVzY2FwYXIgZGUgbG9zIG3DrW5pbW9zIGxvY2FsZXMgaGFzdGEgYWNlcmNhcnNlIGFsIMOzcHRpbW8gZ2xvYmFsLCBxdWUgc2UgZW5jdWVudHJhIGVuICgwLDApKDAsMCkuDQoNCjo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJQYXJ0ZSAxXEV2b2x1Y2lvbl9EaWZlcmVuY2lhbFxyYXN0cmlnaW5fb3B0X2V2ZF8yZC5naWYiIGFsdD0iQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJhc3RyaWdpbiAyRCIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQNCjo6Og0KOjo6Og0KDQpSZXN1bHRhZG8gb2J0ZW5pZG86IFsxXSAyLjE3NjY5N2UtMDYgLTIuMDE1Nzg1ZS0wNyBWYWxvciBtw61uaW1vOiA5LjQ4ZS0xMA0KDQo8YSBuYW1lPSJpbzEuMy41LiI+PC9hPg0KDQojIyMgMS4zLjUgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMyBkaW1lbnNpb25lcw0KDQpFbiBlc3RlIGNhc28sIGVsIGFsZ29yaXRtbyBlbmNvbnRyw7MgdW5hIHNvbHVjacOzbiBjZXJjYW5hIGFsIG3DrW5pbW8gZ2xvYmFsLCBhdW5xdWUgbm8gZXhhY3RhLiBFc3RvIGVzIGVzcGVyYWJsZSwgeWEgcXVlIFJhc3RyaWdpbiBlcyBtdWNobyBtw6FzIGRpZsOtY2lsIGVuIDNEIGRlYmlkbyBhIGxhIGdyYW4gY2FudGlkYWQgZGUgbcOtbmltb3MgbG9jYWxlcy4NCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRXZvbHVjaW9uX0RpZmVyZW5jaWFsL3Jhc3RyaWdpbl9pdGVyX2V2ZC5jc3YiKQ0KYGBgDQoNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8ICAgICB8IEl0ZXJhY2lvbiB8IFgxICAgICAgICAgICB8IFgyICAgICAgICAgICB8IFgzICAgICAgICAgICB8IGZfeCAgICAgICAgfA0KfCAgICAgfCAgICAgICAgICAgfCAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgfCAgICAgICAgICAgIHwNCnwgICAgIHwgXDxpbnRcPiAgIHwgXDxkYmxcPiAgICAgIHwgXDxkYmxcPiAgICAgIHwgXDxkYmxcPiAgICAgIHwgXDxkYmxcPiAgICB8DQorPT09PT0rPT09PT09PT09PTorPT09PT09PT09PT09PTorPT09PT09PT09PT09PTorPT09PT09PT09PT09PTorPT09PT09PT09PT06Kw0KfCAxMCAgfCAxMCAgICAgICAgfCAxLjA2NDMzNDU2MSAgfCAxLjAzNzk3MTQ2NCAgfCAtMC4wODYwNTY3NDUgfCA0LjczMzM1NDUwIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDIwICB8IDIwICAgICAgICB8IDEuMDU3MzEzMjA0ICB8IDEuMDEyMDUwMDY2ICB8IDAuMDIxNzMzMjc3ICB8IDIuOTA1Nzg1MjkgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgMzAgIHwgMzAgICAgICAgIHwgMS4wNTczMTMyMDQgIHwgMS4wMTIwNTAwNjYgIHwgMC4wMjE3MzMyNzcgIHwgMi45MDU3ODUyOSB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCA0MCAgfCA0MCAgICAgICAgfCAwLjAzNjI0NjgwOCAgfCAxLjAzMTQyODUwMyAgfCAxLjAwOTU3NjgxMiAgfCAyLjU1NTA2NDYzIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDUwICB8IDUwICAgICAgICB8IC0xLjAwNDcyMDQ5MCB8IC0wLjAyNTY3NzI2OSB8IDAuMDIyOTk3ODgzICB8IDEuMjQ5MTMyMjQgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgNjAgIHwgNjAgICAgICAgIHwgMC45ODg0OTk1NDIgIHwgLTAuMDA4NjUxNTE4IHwgMC4wMTAyNTgwNzIgIHwgMS4wMzg5NDIxNiB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCA3MCAgfCA3MCAgICAgICAgfCAwLjk4ODQ5OTU0MiAgfCAtMC4wMDg2NTE1MTggfCAwLjAxMDI1ODA3MiAgfCAxLjAzODk0MjE2IHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDgwICB8IDgwICAgICAgICB8IC0wLjAyNTA3NTI3NyB8IDAuMDQxMDcxNDQ3ICB8IDAuMDIwMDE2ODg1ICB8IDAuNTM2Njg5NzEgfA0KKy0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgOTAgIHwgOTAgICAgICAgIHwgMC4wMTA1MjQxMTQgIHwgMC4wMDk5NDEwNDEgIHwgMC4wMDYyMTUzMjQgIHwgMC4wNDkyMjc5MyB8DQorLS0tLS0rLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCAxMDAgfCAxMDAgICAgICAgfCAtMC4wMDQwNjEyNTkgfCAtMC4wMDc1MDQyNjcgfCAwLjAwMTI0NDgwMCAgfCAwLjAxNDc0OTY4IHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQoNCioqVGFibGEgNC4qKiBUYWJsYSBkZSBlamVjdWNpw7NuIGRlIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDNEIHV0aWxpemFuZG8gRXZvbHVjacOzbiBEaWZlcmVuY2lhbA0KDQo8YSBuYW1lPSJpbzEuMy42LiI+PC9hPg0KDQojIyMgMS4zLjYgQ29uY2x1c2lvbmVzIG3DqXRvZG8gZGUgZXZvbHVjacOzbiBkaWZlcmVuY2lhbA0KDQpFbCBhbGdvcml0bW8gbG9ncsOzIGVuY29udHJhciBzb2x1Y2lvbmVzIG11eSBjZXJjYW5hcyBhbCBtw61uaW1vIGdsb2JhbCBlbiBsYXMgZnVuY2lvbmVzIGRlIFJvc2VuYnJvY2sgeSBSYXN0cmlnaW4sIHRhbnRvIGVuIDJEIGNvbW8gZW4gM0QuDQoNCkVuIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2ssIHNlIG9ic2VydsOzIHVuYSBjb252ZXJnZW5jaWEgZXN0YWJsZSB5IHByZWNpc2EsIGVzcGVjaWFsbWVudGUgZW4gZG9zIGRpbWVuc2lvbmVzLg0KDQpFbiBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4sIHF1ZSBwcmVzZW50YSBtdWNob3MgbcOtbmltb3MgbG9jYWxlcywgZWwgbcOpdG9kbyBldml0w7MgY2FlciBlbiBlc3RvcyB5IGFsY2FuesOzIGJ1ZW5vcyByZXN1bHRhZG9zLg0KDQpFbCByZW5kaW1pZW50byBzZSBtYW50dXZvIHPDs2xpZG8gZW4gdHJlcyBkaW1lbnNpb25lcywgYXVucXVlIGNvbiB1bmEgbGlnZXJhIHDDqXJkaWRhIGRlIHByZWNpc2nDs24gZW4gUmFzdHJpZ2luIDNEIGRlYmlkbyBhIHN1IGNvbXBsZWppZGFkLg0KDQpGdWUgbcOhcyByb2J1c3RvIHF1ZSBlbCBkZXNjZW5zbyBwb3IgZ3JhZGllbnRlIGVuIGZ1bmNpb25lcyBtdWx0aW1vZGFsZXMsIHlhIHF1ZSBubyBuZWNlc2l0YSBkZXJpdmFkYXMgbmkgZGVwZW5kZSBkZWwgcHVudG8gaW5pY2lhbC4NCg0KTGEgZXZvbHVjacOzbiBkaWZlcmVuY2lhbCBkZW1vc3Ryw7Mgc2VyIHVuIG3DqXRvZG8gY29uZmlhYmxlIHkgZWZlY3Rpdm8gcGFyYSByZXNvbHZlciBwcm9ibGVtYXMgZGUgb3B0aW1pemFjacOzbsKgY29udGludWEuDQoNCjxhIG5hbWU9ImlvMS40LiI+PC9hPg0KDQojIyAxLjQgTcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzDQoNCkVsIG3DqXRvZG8gZGUgb3B0aW1pemFjacOzbiBwb3IgZW5qYW1icmUgZGUgcGFydMOtY3VsYXMgKFBTTywgcG9yIHN1cyBzaWdsYXMgZW4gaW5nbMOpcykgZXMgdW4gYWxnb3JpdG1vIGluc3BpcmFkbyBlbiBlbCBjb21wb3J0YW1pZW50byBjb2xlY3Rpdm8gZGUgYW5pbWFsZXMgY29tbyBiYW5kYWRhcyBkZSBhdmVzIG8gYmFuY29zIGRlIHBlY2VzLiBGdW5jaW9uYSBtZWRpYW50ZSB1biBjb25qdW50byBkZSBwYXJ0w61jdWxhcyAoc29sdWNpb25lcyBwb3RlbmNpYWxlcykgcXVlIGV4cGxvcmFuIGVsIGVzcGFjaW8gZGUgYsO6c3F1ZWRhIG1vdmnDqW5kb3NlIGVuIGZ1bmNpw7NuIGRlIHN1IHByb3BpYSBleHBlcmllbmNpYSB5IGxhIGRlIHN1cyB2ZWNpbmFzLiBDYWRhIHBhcnTDrWN1bGEgYWp1c3RhIHN1IHBvc2ljacOzbiB5IHZlbG9jaWRhZCBpdGVyYXRpdmFtZW50ZSBwYXJhIGFjZXJjYXJzZSBhIGxhIG1lam9yIHNvbHVjacOzbiBjb25vY2lkYSwgZ3VpYWRhIHBvciBzdSBtZWpvciBwb3NpY2nDs24gaGlzdMOzcmljYSB5IGxhIG1lam9yIHBvc2ljacOzbiBnbG9iYWwgZW5jb250cmFkYSBwb3IgZWwgZW5qYW1icmUuIENvbiBlbCB0aWVtcG8sIGxhcyBwYXJ0w61jdWxhcyB0aWVuZGVuIGEgY29udmVyZ2VyIGhhY2lhIHVuYSBzb2x1Y2nDs24gw7NwdGltYSBvIGNlcmNhbmEgYWwgw7NwdGltby4NCg0KPGEgbmFtZT0iaW8xLjQuMS4iPjwvYT4NCg0KIyMjIDEuNC4xIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIG9wdGltaXphY2nDs24gZGUgcGFydMOtY3VsYXMNCg0KU2UgdXRpbGl6YSBlbCBwYXF1ZXRlIHBvcyBwYXJhIGltcGxlbWVudGFyIGVsIG3DqXRvZG8gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBwYXJ0w61jdWxhcy4gQWRpY2lvbmFsbWVudGUsIHNlIGltcGxlbWVudGEgdW5hIGZ1bmNpw7NuIGFkaWNpb25hbCBwYXJhIGNyZWFyIGxhcyBhbmltYWNpb25lcyBkZWwgbcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuLg0KDQo8YSBuYW1lPSJpbzEuNC4yLiI+PC9hPg0KDQojIyMgMS40LjIgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXMNCg0KOjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KPGltZyBzcmM9InBzb19yb3NlbmJyb2NrX21pbi5naWYiIGFsdD0iQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJvc2VuYnJvY2sgMkQgY29uIFBTTyIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDJEIGNvbiBQU08NCjo6Og0KOjo6Og0KDQo8YSBuYW1lPSJpbzEuNC4zLiI+PC9hPg0KDQojIyMgMS40LjMgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDMgZGltZW5zaW9uZXMNCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvRW5qYW1icmUgZGUgcGFydMOtY3VsYXMvcm9zZW5icm9ja19pdGVyX3Bzby5jc3YiKQ0KYGBgDQoNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgICAgIHwgaXRlcmFjaW9uIHwgbWVqb3JfdmFsb3JfZW5qYW1icmUgfCBtZWpvcl9wb3NpY2lvbl9lbmphbWJyZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGRpZmVyZW5jaWFfYWJzIHwNCnwgICAgIHwgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgIHwNCnwgICAgIHwgXDxpbnRcPiAgIHwgXDxkYmxcPiAgICAgICAgICAgICAgfCBcPGNoclw+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IFw8ZGJsXD4gICAgICAgIHwNCis9PT09PSs9PT09PT09PT09Ois9PT09PT09PT09PT09PT09PT09PT06Kzo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0rPT09PT09PT09PT09PT09OisNCnwgMTAgIHwgMTAgICAgICAgIHwgMzMxLjc2NjYgICAgICAgICAgICAgfCAtOS41MTM1NTI3NzM2NTY0MywgOS41NTYyNzI5NDkwNTg1OSwgOS41MjM4MTgzMzQ5MjI4NCB8IDEuNDY2OTU1ZS0wMSAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgMjAgIHwgMjAgICAgICAgIHwgMzMxLjc5NDEgICAgICAgICAgICAgfCAtOS41NDU0NTUwNDkxNDYwMywgOS41ODM0MTM2MDY4MTEyNCwgOS41MjMwNjE2NDE4NzI4NCB8IDIuMTM2MjcyZS0wMSAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgMzAgIHwgMzAgICAgICAgIHwgMzMyLjA2OTggICAgICAgICAgICAgfCAtOS41MzU5MDExMzI0MTcyNywgOS41NDA0MTU3NzU4ODY1MywgOS41NjAxMTc2NTYyOTExMiB8IDQuNDQ0NjkyZS0wMSAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgNDAgIHwgNDAgICAgICAgIHwgMzMxLjc0MzcgICAgICAgICAgICAgfCAtOS41MjQyMzI2ODQzNTk0OCwgOS41MjcyNTcyNTM5NDE1NCwgOS41ODExODg3MjkwNTM2ICB8IDMuMDAxNTcwZS0wMSAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgNTAgIHwgNTAgICAgICAgIHwgMzMxLjgyMDMgICAgICAgICAgICAgfCAtOS41MTQyNTQxMjgyOTMxLCA5LjUyOTA4Nzg5NzY0MDIxLCA5LjU0MTU1MzA1Mzk2OTQ4ICB8IDEuNTYwMTYzZS0wMSAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgNjAgIHwgNjAgICAgICAgIHwgMzMyLjAzODMgICAgICAgICAgICAgfCAtOS41NzIwOTIxMjU0MTk2NywgOS41NDQ4MTQ2NzQ1MTA5NywgOS41NDY3NTE1MDc4NzU3MyB8IDguNDIwODg1ZS0wMiAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgNzAgIHwgNzAgICAgICAgIHwgMzMyLjExMTAgICAgICAgICAgICAgfCAtOS41NDQzMDI3MzIwNDEzNiwgOS41Mzc4MjczODM3Njg5NSwgOS41NDkyMTYwNzQyNzMxOSB8IDEuNDU4MjkzZS0wMiAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgODAgIHwgODAgICAgICAgIHwgMzMyLjEzNDcgICAgICAgICAgICAgfCAtOS41NDQyOTE3MjA0NTc2NiwgOS41NDc3NDczNTY2Mjg1NCwgOS41NDk3NjcyMzQ1OTU4MyB8IDEuOTkyNTgxZS0wNCAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgOTAgIHwgOTAgICAgICAgIHwgMzMyLjEzNzUgICAgICAgICAgICAgfCAtOS41NDc0MzExNDQ3ODc2NywgOS41NTIwMTY4NjI1MTI5OSwgOS41NDg4MDQ4MzY1MDczNiB8IDMuMjI3OTk2ZS0wMyAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgMTAwIHwgMTAwICAgICAgIHwgMzMyLjEzOTMgICAgICAgICAgICAgfCAtOS41NTAyMDIxMDQ3ODI3NywgOS41NDg0ODgyNjk3NjMyNywgOS41NDkxOTE2NzI0NDY4MyB8IDIuNjM5MDI3ZSAgICAgIHwNCistLS0tLSstLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCg0KKipUYWJsYSA1LioqIFRhYmxhIGRlIGVqZWN1Y2nDs24gZGUgb3B0aW1pemFjacOzbiBkZSBSb3NlbmJyb2NrIDNEIHV0aWxpemFuZG8gT3B0aW1pemFjacOzbiBkZSBQYXJ0w61jdWxhcw0KDQo8YSBuYW1lPSJpbzEuNC40LiI+PC9hPg0KDQojIyMgMS40LjQgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSYXN0cmlnaW4gZW4gMiBkaW1lbnNpb25lcw0KDQo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo8aW1nIHNyYz0icHNvX3Jhc3RyaWdpbl9taW4uZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIFBTTyIgc3R5bGU9IndpZHRoOjM1MHB4OyBtYXgtd2lkdGg6OTAlOyBkaXNwbGF5OmJsb2NrOyBtYXJnaW46YXV0bzsiLz4NCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCkFuaW1hY2nDs24gZGUgbGEgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIFBTTw0KOjo6DQo6Ojo6DQoNCjxhIG5hbWU9ImlvMS40LjUuIj48L2E+DQoNCiMjIyAxLjQuNSBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAzIGRpbWVuc2lvbmVzDQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcyBhIHV0aWxpemFyDQpuIDwtIDMNCmxvd2VyX2JvdW5kcyA8LSAtNQ0KdXBwZWRfYm91bmRzIDwtIDUNCiMgRWplY3VjacOzbiBkZWwgbcOpdG9kbw0Kb19wc28gPC0gcGFydGljbGVfc3dhcm1fb3B0aW1pemF0aW9uKG4sZl9yYXN0cmlnaW4sbG93ZXJfYm91bmRzLHVwcGVyX2JvdW5kcykNCmBgYA0KDQpgYGB7cn0NCnNob3dfdGFibGUoIi4vUGFydGUgMS9FbmphbWJyZSBkZSBwYXJ0w61jdWxhcy9yYXN0cmlnaW5faXRlcl9wc28uY3N2IikNCmBgYA0KDQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgaXRlcmFjaW9uIHwgbWVqb3JfdmFsb3JfZW5qYW1icmUgfCBtZWpvcl9wb3NpY2lvbl9lbmphbWJyZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgZGlmZXJlbmNpYV9hYnMgfA0KfCAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICB8DQp8IFw8aW50XD4gICB8IFw8ZGJsXD4gICAgICAgICAgICAgIHwgXDxjaHJcPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IFw8ZGJsXD4gICAgICAgIHwNCis9PT09PT09PT09Ois9PT09PT09PT09PT09PT09PT09PT06Kzo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSs9PT09PT09PT09PT09PT06Kw0KfCAxMCAgICAgICAgfCAzMzIuMTMzMyAgICAgICAgICAgICB8IDkuNTUwNjI1MDA4NjQ5MDQsIDkuNTQ3MzYxNTU4NDI1MDIsIDkuNTU0NDg3NjM5NzUwMDQgfCAxLjMyNTg3M2UrMDAgICB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgMjAgICAgICAgIHwgMzMxLjU0MDYgICAgICAgICAgICAgfCA5LjUyMzU3NDQ2OTU4NzI3LCA5LjU2Njg1ODIxMzE3NTQyLCA5LjUwMjUwMjA1Nzg0MDk0IHwgNC43OTIwNjVlLTAxICAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0rDQp8IDMwICAgICAgICB8IDMzMS41NzkxICAgICAgICAgICAgIHwgOS41NjUyNjA5MTI1OTU4NiwgOS42MDAxMTQ2ODcwMzcsIDkuNTY1MTg1MDQ1MzAxNTIgICB8IDIuNzA3ODM2ZS0wMSAgIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tKw0KfCA0MCAgICAgICAgfCAzMzEuOTg2NSAgICAgICAgICAgICB8IDkuNTc2ODI1OTMwNDcwMjMsIDkuNTUyNjMwNjQ0Nzc0OSwgOS41NDE2MzY3OTQyOTgxNyAgfCAxLjM5OTQ2OGUtMDEgICB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgNTAgICAgICAgIHwgMzMxLjk4MTggICAgICAgICAgICAgfCA5LjUyMjgzODg5NDA3NzMsIDkuNTQwMjU0NzIyNDI5OTYsIDkuNTQxMzc3NTM4NjYxMSAgIHwgMy4wODIwMjBlLTAxICAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0rDQp8IDYwICAgICAgICB8IDMzMi4wOTUyICAgICAgICAgICAgIHwgOS41NjQ2MTE4NzgzMjk5NSwgOS41NDgxNTk5OTUyMDQ3NywgOS41NDg4MzY4MTk4Mjg1NiB8IDEuNzUzMDMzZS0wMiAgIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tKw0KfCA3MCAgICAgICAgfCAzMzIuMTI2NiAgICAgICAgICAgICB8IDkuNTU1ODAwNjc4NjM5OTQsIDkuNTUyMzY1NjMyNDk3LCA5LjU0NTI4NjA2MjgzNzY3ICAgfCA1LjU2MTUyOWUtMDMgICB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCnwgODAgICAgICAgIHwgMzMyLjEzODcgICAgICAgICAgICAgfCA5LjU0NzUwMzYyMzQ5MzY5LCA5LjU0ODg0MjQwODM0NDEsIDkuNTUwNDcxMTIyMTAzMzUgIHwgMy40OTc0NzJlLTA0ICAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0rDQp8IDkwICAgICAgICB8IDMzMi4xMzkxICAgICAgICAgICAgIHwgOS41NDc5Mjc2MDIzMzgzOSwgOS41NDg4MjU4NDk0NTcxOCwgOS41NDgyMDI4MjQyMzczOSB8IDEuMzMyNzc5ZS0wNCAgIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tKw0KfCAxMDAgICAgICAgfCAzMzIuMTM5MyAgICAgICAgICAgICB8IDkuNTQ4MzMxNzYzNTk4MTQsIDkuNTQ4OTE5Mjc5MjI2MzQsIDkuNTQ4Mjg3NDA5MjU1NzIgfCAxLjkyNDM4MGUtMDUgICB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLSsNCg0KKipUYWJsYSA2LioqIFRhYmxhIGRlIGVqZWN1Y2nDs24gZGUgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gM0QgdXRpbGl6YW5kbyBPcHRpbWl6YWNpw7NuIGRlIFBhcnTDrWN1bGFzDQoNCjxhIG5hbWU9ImlvMS40LjYuIj48L2E+DQoNCiMjIyAxLjQuNiBDb25jbHVzaW9uZXMgbcOpdG9kbyBkZSBvcHRpbWl6YWNpw7NuIGRlIHBhcnTDrWN1bGFzDQoNCkVuIGVsIGNhc28gZGUgbGEgb3B0aW1pemFjacOzbiBtYXhpbWl6YW5kbyBsYXMgZnVuY2lvbmVzLCBsbGVnYW4gbXV5IHLDoXBpZG8gYSB1bmEgc29sdWNpw7NuIMOzcHRpbWEgKGRlbnRybyBkZSAxMCBpdGVyYWNpb25lcykuIFBvciBvdHJvIGxhZG8sIGxhIG9wdGltaXphY2nDs24gbWluaW1pemFuZG8gbGFzIGZ1bmNpb25lcyB0YXJkYWJhIHVuIHBvY28gbcOhcyBlbiBsbGVnYXIgYWwgw7NwdGltbywgcGVybyBzZSBhY2VyY2FiYSBtdWNobyBhbCBtw61uaW1vIGdsb2JhbC4NCg0KRXN0b3MgcmVzdWx0YWRvcyBwdWVkZW4gZGViZXJzZSBhIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIHBhcnTDrWN1bGFzIHBvciBlbCBlc3BhY2lvIGRlIGLDunNxdWVkYSwgcGVybWl0aWVuZG8gdW5hIG9wdGltaXphY2nDs24gbcOhcyAiYWJpZXJ0YSIgYSBjb21wYXJhY2nDs24gY29uIGVsIG3DqXRvZG8gZGUgZGVzY2Vuc28gZGUgZ3JhZGllbnRlLg0KDQo8YSBuYW1lPSJpbzEuNS4iPjwvYT4NCg0KIyMgMS41IE3DqXRvZG8gZGUgYWxnb3JpdG1vcyBldm9sdXRpdm9zDQoNCkxvcyBhbGdvcml0bW9zIGdlbsOpdGljb3MgKEFHKSBzb24gdMOpY25pY2FzIGRlIGLDunNxdWVkYSBoZXVyw61zdGljYSBiYXNhZGFzIGVuIHByb2Nlc29zIGRlIGV2b2x1Y2nDs24gbmF0dXJhbOKAiyAuIEVuIHVuIEFHIHTDrXBpY28gc2UgZGVmaW5lIHVuYSBmdW5jacOzbiBGSVRORVNTIHF1ZSBldmFsw7phIGxhIGNhbGlkYWQgZGUgY2FkYSBzb2x1Y2nDs24gY2FuZGlkYXRhIChpbmRpdmlkdW8pLiBBIHBhcnRpciBkZSB1bmEgcG9ibGFjacOzbiBpbmljaWFsIGFsZWF0b3JpYSwgc2UgaXRlcmFuIGNpY2xvcyBkb25kZSBzZSBzZWxlY2Npb25hbiBpbmRpdmlkdW9zIG3DoXMgYXB0b3MsIHNlIGNvbWJpbmFuIHN1cyAiZ2VuZXMiIG1lZGlhbnRlIGNydWNlcyAoY3Jvc3NvdmVyKSB5IHNlIGludHJvZHVjZW4gbW9kaWZpY2FjaW9uZXMgYWxlYXRvcmlhcyAobXV0YWNpb25lcykuIEVzdG9zIG9wZXJhZG9yZXMgZXZvbHVjaW9uYW4gbGEgcG9ibGFjacOzbiBoYWNpYSByZWdpb25lcyBjb24gbWVqb3IgZml0bmVzcy4NCg0KU2Vnw7puIChTY3J1Y2NhLCAyMDEzKSwgbG9zIEdBcyBoYW4gc2lkbyBleGl0b3NvcyBlbiBvcHRpbWl6YXIgZnVuY2lvbmVzIGNvbnRpbnVhcyAoZGlmZXJlbmNpYWJsZXMgbyBubykgeSBkaXNjcmV0YXMuIEVudHJlIGxvcyBvcGVyYWRvcmVzIGdlbsOpdGljb3MgY2xhdmUgc2UgZGVzdGFjYW46DQoNCi0gICBTZWxlY2Npw7NuOiBlbGlnZSBpbmRpdmlkdW9zIGNvbiBtYXlvciBmaXRuZXNzIHBhcmEgcmVwcm9kdWNpcnNlLCBpbWl0YW5kbyBsYSBzdXBlcnZpdmVuY2lhIGRlbCBtw6FzIGFwdG8uDQoNCi0gICBDcnVjZSAoY3Jvc3NvdmVyKTogY29tYmluYSBwYXJ0ZXMgZGUgZG9zIHNvbHVjaW9uZXMgcGFyZW50YWxlcyBwYXJhIGdlbmVyYXIgZGVzY2VuZGVuY2lhLCBleHBsb3JhbmRvIG51ZXZhcyByZWdpb25lcyBkZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEuDQoNCi0gICBNdXRhY2nDs246IGFsdGVyYSBhbGVhdG9yaWFtZW50ZSBwYXJ0ZSBkZSB1biBpbmRpdmlkdW8gKHBvciBlamVtcGxvLCBjYW1iaWFuZG8gdW4gdmFsb3IgZGUgc3UgdmVjdG9yIGRlIHZhcmlhYmxlcykgcGFyYSBpbnRyb2R1Y2lyIGRpdmVyc2lkYWQgZ2Vuw6l0aWNhIHkgZXZpdGFyIGVzdGFuY2FtaWVudG8gZW4gw7NwdGltb3MgbG9jYWxlcy4NCg0KTG9zIGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcyAoQUcpIHNvbiBtZXRhaGV1csOtc3RpY2FzIGluc3BpcmFkYXMgZW4gcHJvY2Vzb3MgZXZvbHV0aXZvcyBiaW9sw7NnaWNvcywgcXVlIGhhbiBkZW1vc3RyYWRvIGVmaWNhY2lhIGVuIGxhIGLDunNxdWVkYSBnbG9iYWwgZGUgw7NwdGltb3MgZW4gZnVuY2lvbmVzIGNvbXBsZWphc+KAi2pzdGF0c29mdC5vcmcgTG9zIEFHIHNpbXVsYW4gbGEgc2VsZWNjacOzbiBuYXR1cmFsLCBsYSByZWNvbWJpbmFjacOzbiAoY3J1Y2UpIHkgbGEgbXV0YWNpw7NuIHBhcmEgaXRlcmF0aXZhbWVudGUgbWVqb3JhciB1biBjb25qdW50byBkZSBzb2x1Y2lvbmVzIGNhbmRpZGF0YXMgKHBvYmxhY2nDs24pLiBFc3RhcyB0w6ljbmljYXMgZXN0b2PDoXN0aWNhcyBzb24gYWRlY3VhZGFzIHBhcmEgZnVuY2lvbmVzIG5vIGxpbmVhbGVzLCBkaXNjb250aW51YXMgbyBjb24gbcO6bHRpcGxlcyDDs3B0aW1vcyBsb2NhbGVzIGRvbmRlIGxvcyBtw6l0b2RvcyBiYXNhZG9zIGVuIGRlcml2YWRhcyBwdWVkZW4gZmFsbGFyLiBQYXJhIGV2YWx1YXIgbGEgcm9idXN0ZXogZGUgbG9zIEdBLCBzZSByZWFsaXphcsOhbiBtw7psdGlwbGVzIGVqZWN1Y2lvbmVzIGluZGVwZW5kaWVudGVzIHkgc2UgYW5hbGl6YXLDoSBsYSBkaXNwZXJzacOzbiBkZWwgZml0bmVzcyByZXN1bHRhbnRlLg0KDQpBZGljaW9uYWxtZW50ZSwgc2UgZGVmaW5lbiBhbGd1bmFzIGZ1bmNpb25lcyBwYXJhIHBvZGVyIG1vc3RyYXIgcG9yIG1lZGlvIGRlIHVuYSBhbmltYWNpw7NuIGVsIHByb2Nlc28gZGUgb3B0aW1pemFjacOzbiBwYXJhIGxhcyBmdW5jaW9uZXMgZGUgUm9zZW5icm9jayB5IGRlIFJhc3RyaWdpbi4NCg0KQW5hbGl6YXJlbW9zIGNhZGEgZnVuY2nDs24gZW4gMiB5IDMgZGltZW5zaW9uZXMsIGdyYWZpY2FuZG8gc3UgcGFpc2FqZSBhbnRlcyBkZSBsYSBvcHRpbWl6YWNpw7NuIHkgbHVlZ28gYXBsaWNhbmRvIHVuIEFHIGNvbiBtw7psdGlwbGVzIGNvcnJpZGFzIHBhcmEgZXZhbHVhciBsYSByb2J1c3RleiBkZSBsb3MgcmVzdWx0YWRvcy4NCg0KPGEgbmFtZT0iaW8xLjUuMS4iPjwvYT4NCg0KIyMjIDEuNS4xIEltcGxlbWVudGFjacOzbiBlbiBSIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvcw0KDQpTZSB1dGlsaXphIGxhIGZ1bmNpw7NuIGdhKCkgZGVsIHBhcXVldGUgR0EuIFBhcmEgcHJvYmxlbWFzIGRlIG1pbmltaXphY2nDs24gc2UgZGVmaW5lIGxhIGZ1bmNpw7NuIGRlIGZpdG5lc3MgY29tbyBlbCBuZWdhdGl2byBkZWwgdmFsb3Igb2JqZXRpdm8sIHlhIHF1ZSBnYSgpIG1heGltaXphIHBvciBkZWZlY3RvLiBTZSBlc3BlY2lmaWNhbiBsb3MgbMOtbWl0ZXMgZGUgYsO6c3F1ZWRhLg0KDQpMb3MgcmVzw7ptZW5lcyBlbiBjYWRhIGVqZWN1Y2nDs24gcmVwb3J0YW4gZWwgbWVqb3IgZml0bmVzcyBlbmNvbnRyYWRvIChuZWdhdGl2bykgeSBsYSBzb2x1Y2nDs24gw7NwdGltYSBlbiBjYWRhIGVqZWN1Y2nDs24uDQoNCjxhIG5hbWU9ImlvMS41LjIuIj48L2E+DQoNCiMjIyAxLjUuMiBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJhc3RyaWdpbiBlbiAyIGRpbWVuc2lvbmVzDQoNCjo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCjxpbWcgc3JjPSJvcHRpbV9yYXN0cmlnaW5fZ2EuZ2lmIiBhbHQ9IkFuaW1hY2nDs24gZGUgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIEFsZ29yaXRtbyBHZW7DqXRpY28iIHN0eWxlPSJ3aWR0aDozNTBweDsgbWF4LXdpZHRoOjkwJTsgZGlzcGxheTpibG9jazsgbWFyZ2luOmF1dG87Ii8+DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpBbmltYWNpw7NuIGRlIGxhIG9wdGltaXphY2nDs24gZGUgUmFzdHJpZ2luIDJEIGNvbiBBbGdvcml0bW8gR2Vuw6l0aWNvDQo6OjoNCjo6OjoNCg0KPGEgbmFtZT0iaW8xLjUuMy4iPjwvYT4NCg0KIyMjIDEuNS4zIE9wdGltaXphY2nDs24gZGUgbGEgZnVuY2nDs24gZGUgUmFzdHJpZ2luIGVuIDMgZGltZW5zaW9uZXMNCg0KYGBge3J9DQpzaG93X3RhYmxlKCIuL1BhcnRlIDEvQWxnb3JpdG1vc19Fdm9sdXRpdm9zL3Jhc3RyaWdpbl9pdGVyX2FlLmNzdiIpDQpgYGANCg0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCBJdGVyYXRpb24gfCBNZWFuICAgICAgfCBCZXN0ICAgICAgfA0KfCAgICAgICAgICAgfCAgICAgICAgICAgfCAgICAgICAgICAgfA0KfCBcPGludFw+ICAgfCBcPGRibFw+ICAgfCBcPGRibFw+ICAgfA0KKz09PT09PT09PT06Kz09PT09PT09PT06Kz09PT09PT09PT06Kw0KfCAxMCAgICAgICAgfCAtMjcuMjM4NTggfCAtOS4wNDkzNjkgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCAyMCAgICAgICAgfCAtMjUuMTMzODEgfCAtOS4wNDkzNjkgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCAzMCAgICAgICAgfCAtMTguODAzODkgfCAtOS4wMDk4NTQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA0MCAgICAgICAgfCAtMTUuNjEwOTEgfCAtOS4wMDk4NTQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA1MCAgICAgICAgfCAtMTAuNDc0MTQgfCAtOS4wMDk4NTQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA2MCAgICAgICAgfCAtMTYuNTUxNTMgfCAtOS4wMDk4NTQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA3MCAgICAgICAgfCAtMTcuMzg1NDAgfCAtOS4wMDc5MjEgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA4MCAgICAgICAgfCAtMTAuMjg5MTkgfCAtOS4wMDA5MDkgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCA5MCAgICAgICAgfCAtMTYuNzUwMTIgfCAtOS4wMDA1MDQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KfCAxMDAgICAgICAgfCAtMTIuMzAzMDIgfCAtOS4wMDAzNDQgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tKw0KDQoqKlRhYmxhIDcuKiogVGFibGEgZGUgZWplY3VjacOzbiBkZSBvcHRpbWl6YWNpw7NuIGRlIFJhc3RyaWdpbiAzRCB1dGlsaXphbmRvIEFsZ29yaXRtb3MgRXZvbHV0aXZvcw0KDQo8YSBuYW1lPSJpbzEuNS40LiI+PC9hPg0KDQojIyMgMS41LjQgT3B0aW1pemFjacOzbiBkZSBsYSBmdW5jacOzbiBkZSBSb3NlbmJyb2NrIGVuIDIgZGltZW5zaW9uZXMNCg0KIyMjIA0KDQo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQohWyoqRmlndXJhIDEyLioqIEFuaW1hY2nDs24gZGUgb3B0aW1pemFjacOzbiBkZSBSYXN0cmlnaW4gMkQgY29uIEFsZ29yaXRtbyBHZW7DqXRpY28uXShpbWFnZXMvb3B0aW1fcmFzdHJpZ2luX2dhLTAyLmdpZikNCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCioqQW5pbWFjacOzbiBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIFJvc2VuYnJvY2sgMkQgY29uIEFsZ29yaXRtbyBHZW7DqXRpY28qKg0KOjo6DQo6Ojo6DQoNCjxhIG5hbWU9ImlvMS41LjUuIj48L2E+DQoNCiMjIyAxLjUuNSBPcHRpbWl6YWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGRlIFJvc2VuYnJvY2sgZW4gMyBkaW1lbnNpb25lcw0KDQpgYGB7cn0NCnNob3dfdGFibGUoIi4vUGFydGUgMS9BbGdvcml0bW9zX0V2b2x1dGl2b3Mvcm9zZW5icm9ja19pdGVyX2FlLmNzdiIpDQpgYGANCg0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IEl0ZXJhdGlvbiB8IE1lYW4gICAgICAgfCBCZXN0ICAgICAgIHwNCnwgICAgICAgICAgIHwgICAgICAgICAgICB8ICAgICAgICAgICAgfA0KfCBcPGludFw+ICAgfCBcPGRibFw+ICAgIHwgXDxkYmxcPiAgICB8DQorPT09PT09PT09PTorPT09PT09PT09PT06Kz09PT09PT09PT09OisNCnwgMTAgICAgICAgIHwgLTE5ODYuOTYwNSB8IC0zMS4zOTg3MjAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDIwICAgICAgICB8IC00NTYuNDQ3MSAgfCAtMzEuMzk4NzIwIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCAzMCAgICAgICAgfCAtMTY1Ni42OTQ0IHwgLTMxLjM5ODcyMCB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgNDAgICAgICAgIHwgLTc4MS4wMjM0ICB8IC0yMi45NDExMzAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDUwICAgICAgICB8IC0zMTYuNDA0NSAgfCAtMTUuOTIwNzcwIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCA2MCAgICAgICAgfCAtNzIxLjgzNDEgIHwgLTE0LjA0MzAzMCB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgNzAgICAgICAgIHwgLTk0MS42ODQ4ICB8IC01Ljc1NjUwMCAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQp8IDgwICAgICAgICB8IC0xNTAxLjMxNTQgfCAtNC4xMzA4MDcgIHwNCistLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKw0KfCA5MCAgICAgICAgfCAtMzk2LjQ3MDAgIHwgLTEuMzI3MDc3ICB8DQorLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSsNCnwgMTAwICAgICAgIHwgLTExMzguMDg0MiB8IC0xLjMyNzA3NyAgfA0KKy0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0rDQoNCioqVGFibGEgOC4qKiBUYWJsYSBkZSBlamVjdWNpw7NuIGRlIG9wdGltaXphY2nDs24gZGUgUm9zZW5icm9jayAzRCB1dGlsaXphbmRvIEFsZ29yaXRtb3MgRXZvbHV0aXZvcw0KDQo8YSBuYW1lPSJpbzEuNS42LiI+PC9hPg0KDQojIyMgMS41LjYgQ8OhbGN1bG8gZGUgZXN0YWTDrXN0aWNhcyB5IGFuw6FsaXNpcw0KDQpQYXJhIGV2YWx1YXIgbGEgdmFyaWFiaWxpZGFkIGRlbCBtw6l0b2RvIGVzdG9jw6FzdGljbywgc2UgcmVwaXRlIGNhZGEgY2FzbyBhbCBtZW5vcyAzMCB2ZWNlcyBjb24gc2VtaWxsYXMgZGlzdGludGFzLiBTZSByZWdpc3RyYSBlbCBtZWpvciB2YWxvciBkZSBmaXRuZXNzICh2YWxvcml6YWRvIHBvc2l0aXZhbWVudGUpIG9idGVuaWRvIGVuIGNhZGEgY29ycmlkYS4gU2UgY2FsY3VsYXLDoW4gZXN0YWTDrXN0aWNhcyAobWVkaWEgeSBkZXN2aWFjacOzbiBlc3TDoW5kYXIpIGRlbCBtZWpvciB2YWxvciBkZSBmaXRuZXNzIG9idGVuaWRvIGVuIDMwIGVqZWN1Y2lvbmVzIGluZGVwZW5kaWVudGVzIGRlIGNhZGEgY2FzbyB5IHNlIHJlc3VtaXLDoW4gZW4gdW5hIHRhYmxhLg0KDQpDb24gbG9zIHZlY3RvcmVzIGRlIG1lam9yZXMgdmFsb3JlcyAoYmVzdF92YWxzX3JvcywgZXRjLiksIHNlIGNhbGN1bGFuIGxhIG1lZGlhIHkgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlIGNhZGEgY29uanVudG8gZGUgMzAgcmVzdWx0YWRvcy4gUG9yIGVqZW1wbG8sIG1lYW5fcm9zIHkgc2Rfcm9zIGFycmliYSB5IGxhcyBkZW1hcywgUGFyYSBhc2kgcHJlc2VudGFyIGxvcyByZXN1bHRhZG9zLg0KDQpMb3MgcmVzdWx0YWRvcyBkZSBsYXMgbcO6bHRpcGxlcyBlamVjdWNpb25lcyBzZSByZXN1bWVuIGVuIGxhIFRhYmxhIDEuIEVzdGEgdGFibGEgbXVlc3RyYSBsYSBtZWRpYSB5IGRlc3ZpYWNpw7NuIGVzdMOhbmRhciBkZWwgbWVqb3IgdmFsb3IgZGUgZml0bmVzcyAocmVjb3JkYWRvIHF1ZSBlcyBlbCB2YWxvciBkZSBsYSBmdW5jacOzbiBvYmpldGl2byBlbiBzdSBtw61uaW1vIGdsb2JhbCwgdMOtcGljYW1lbnRlIGNlcmNhbm8gYSAwKSBwYXJhIGNhZGEgY29tYmluYWNpw7NuIGRlIGZ1bmNpw7NuIHkgZGltZW5zacOzbi4gU2Ugb2JzZXJ2YSBxdWUgcGFyYSBSb3NlbmJyb2NrIDJELCBsYSBtZWRpYSBkZWwgZml0bmVzcyBtw61uaW1vIGVzIGNlcmNhbmEgYSAwIGNvbiBiYWphIGRpc3BlcnNpw7NuLCByZWZsZWphbmRvIHF1ZSBlbCBHQSBub3JtYWxtZW50ZSBlbmN1ZW50cmEgZWwgbcOtbmltbyBnbG9iYWwgKDApIG8gY2VyY2Fuby4gUGFyYSBSYXN0cmlnaW4gMkQsIGxhIG1lZGlhIHRhbWJpw6luIHB1ZWRlIGFjZXJjYXJzZSBhIDAsIHBlcm8gY29uIG1heW9yIGRlc3ZpYWNpw7NuIGVzdMOhbmRhciBkZWJpZG8gYSBsb3MgbcO6bHRpcGxlcyBtw61uaW1vcyBsb2NhbGVzLiBFbiAzRCBhbWJvcyBwcm9ibGVtYXMgc3VlbGVuIG1vc3RyYXIgdmFsb3JlcyBtZWRpb3MgbWF5b3JlcyAobcOhcyBhbGVqYWRvcyBkZSAwKSB5IG1heW9yIHZhcmlhYmlsaWRhZCwgbG8gY3VhbCBpbmRpY2EgdW5hIG1heW9yIGRpZmljdWx0YWQgZGUgYsO6c3F1ZWRhIGFsIGF1bWVudGFyIGxhIGRpbWVuc2lvbmFsaWRhZC4NCg0KfCBGdW5jacOzbiAgICB8IERpbWVuc2nDs24gfCBNZWRpYSAgICAgfCBTRCAgICAgICAgfA0KfC0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgUm9zZW5icm9jayB8IDJEICAgICAgICB8IDAuMDI4NTkwNCB8IDAuMDQ2MDM3MiB8DQp8IFJhc3RyaWdpbiAgfCAyRCAgICAgICAgfCAwLjAwMDE0OTQgfCAwLjAwMDQwMjcgfA0KfCBSb3NlbmJyb2NrIHwgM0QgICAgICAgIHwgMy4zNzc3Mzc1IHwgMi44MDQ2NDUwIHwNCnwgUmFzdHJpZ2luICB8IDNEICAgICAgICB8IDkuMDAwMjQ3MCB8IDAuMDAwOTkxMyB8DQoNCioqVGFibGEgOS4qKiBFc3RhZMOtc3RpY2FzIChtZWRpYSB5IGRlc3ZpYWNpw7NuIGVzdMOhbmRhcikgZGVsIGZpdG5lc3MgbcOtbmltbyBhbGNhbnphZG8gZW4gMzAgY29ycmlkYXMgaW5kZXBlbmRpZW50ZXMgcGFyYSBjYWRhIGZ1bmNpw7NuIHkgZGltZW5zacOzbi4NCg0KPGEgbmFtZT0iaW8xLjUuNy4iPjwvYT4NCg0KIyMjIDEuNS43IENvbmNsdXNpb25lcyBtw6l0b2RvIGRlIGFsZ29yaXRtb3MgZXZvbHV0aXZvcw0KDQpMb3MgcmVzdWx0YWRvcyBjb25maXJtYW4gcXVlIGVsIGFsZ29yaXRtbyBnZW7DqXRpY28gZXMgY2FwYXogZGUgYXByb3hpbWFyc2UgYSBsb3MgbcOtbmltb3MgZ2xvYmFsZXMgZGUgYW1ib3MgcHJvYmxlbWFzIGVuIG3Dumx0aXBsZXMgZGltZW5zaW9uZXMuIENvbW8gZXJhIGRlIGVzcGVyYXIsIFJhc3RyaWdpbiBtb3N0csOzIG1heW9yIHZhcmlhYmlsaWRhZCBlbiBsb3MgdmFsb3JlcyBkZSBmaXRuZXNzIGRlYmlkbyBhIHN1cyBtdWNob3MgbcOtbmltb3MgbG9jYWxlcywgbG8gcXVlIGltcGxpY2EgcXVlIGFsZ3VuYXMgZWplY3VjaW9uZXMgZGVsIEdBIHB1ZWRlbiBxdWVkYXJzZSBhdHJhcGFkYXMgZW4gw7NwdGltb3MgbG9jYWxlcyBhbGVqYWRvcyBkZWwgZ2xvYmFsLiBFbiBjb250cmFzdGUsIFJvc2VuYnJvY2sgKGF1bnF1ZSBlcyBubyBjb252ZXhhKSB0aWVuZGUgYSB1biDDum5pY28gdmFsbGUgcHJpbmNpcGFsOyBwb3IgZWxsbywgbGEgbWF5b3LDrWEgZGUgbGFzIGNvcnJpZGFzIGFsY2FuemFyb24gdmFsb3JlcyBjZXJjYW5vcyBhbCBtw61uaW1vIGdsb2JhbCBjb24gbWVub3IgZGlzcGVyc2nDs24uIEVuIGdlbmVyYWwgc2Ugb2JzZXJ2YSBxdWUgYWwgYXVtZW50YXIgbGEgZGltZW5zacOzbiAoZGUgMkQgYSAzRCkgbGEgdGFyZWEgc2UgY29tcGxpY2EgeSBsYSBtZWRpYSBkZWwgZml0bmVzcyBhdW1lbnRhIChwZW9yIMOzcHRpbW8gZW5jb250cmFkbyksIHJlZmxlamFuZG8gbGEgbWFsZGljacOzbiBkZSBsYSBkaW1lbnNpb25hbGlkYWQuIEVsIHVzbyBkZSBtw7psdGlwbGVzIGVqZWN1Y2lvbmVzIGluZGVwZW5kaWVudGVzIGVzIGVzZW5jaWFsIHBhcmEgZXZhbHVhciBsYSByb2J1c3RleiBkZSBsb3MgQUcuIERlYmlkbyBhIHN1IG5hdHVyYWxlemEgZXN0b2PDoXN0aWNhLCBjYWRhIGVqZWN1Y2nDs24gcHVlZGUgY29udmVyZ2VyIGEgc29sdWNpb25lcyBkaXN0aW50YXMuIEFsIGFuYWxpemFyIGxhIG1lZGlhIHkgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlIGxvcyBmaXRuZXNzIGZpbmFsZXMgc2Ugb2J0aWVuZSB1bmEgbWVkaWRhIGRlIGZpYWJpbGlkYWQgZGVsIGFsZ29yaXRtbzogdW5hIGJhamEgZGVzdmlhY2nDs24gaW5kaWNhIHJlc3VsdGFkb3MgY29uc2lzdGVudGVzLiBFbiBsYSBsaXRlcmF0dXJhIHNvYnJlIGFsZ29yaXRtb3MgZ2Vuw6l0aWNvcyBzZSByZWNvbm9jZSBxdWUgZW4gbXVjaG9zIGNhc29zIHVuYSBzb2xhIGVqZWN1Y2nDs24gcHVlZGUgbm8gc2VyIHJlcHJlc2VudGF0aXZh4oCLanN0YXRzb2Z0Lm9yZy4gQXVucXVlIHVuIGFuw6FsaXNpcyBjb21wYXJhdGl2byBwcm9mdW5kbyAocC5lai4sIHVzYW5kbyBwb2JsYWNpb25lcyBtw6FzIGdyYW5kZXMgbyBtw7psdGlwbGVzIGNvcnJpZGFzIGVuIHBhcmFsZWxvKSBxdWVkYSBmdWVyYSBkZWwgYWxjYW5jZSBkZSBlc3RlIGRvY3VtZW50bywgbnVlc3Ryb3MgcmVzdWx0YWRvcyBpbHVzdHJhbiBlc3RlIGZlbsOzbWVuby4gRXN0ZSBlc3R1ZGlvIGVzIHJlcHJvZHVjaWJsZTogdG9kbyBlbCBjw7NkaWdvIFIgbmVjZXNhcmlvIGVzdMOhIGluY2x1aWRvLCBwZXJtaXRpZW5kbyBhIG90cm9zIGludmVzdGlnYWRvcmVzIHJlcGxpY2FyIGxvcyBleHBlcmltZW50b3MsIHZhcmlhciBwYXLDoW1ldHJvcyBkZWwgR0EgKHRhc2EgZGUgY3J1Y2UsIG11dGFjacOzbiwgdGFtYcOxbyBkZSBwb2JsYWNpw7NuLCBldGMuKSB5IGNvbXBhcmFyIGNvbiBvdHJvcyBhbGdvcml0bW9zIGRlIG9wdGltaXphY2nDs24uOkNvbmNsdXNpb25lcyBTZSBoYSBwcmVzZW50YWRvIHVuYSBkb2N1bWVudGFjacOzbiBjb21wbGV0YSBkZSBsYSBvcHRpbWl6YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgUm9zZW5icm9jayB5IFJhc3RyaWdpbiBlbiAyRCB5IDNEIGVtcGxlYW5kbyBhbGdvcml0bW9zIGdlbsOpdGljb3MgZW4gUi4gTWVkaWFudGUgdmlzdWFsaXphY2lvbmVzIDNEIGluaWNpYWxlcyBzZSBpbHVzdHJhcm9uIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlIGNhZGEgZnVuY2nDs24gZGUgcHJ1ZWJhLiBTZSBpbXBsZW1lbnTDsyBlbCBwYXF1ZXRlIEdBIHBhcmEgcmVzb2x2ZXIgY2FkYSBjYXNvIHkgc2UgcmVhbGl6YXJvbiAzMCBlamVjdWNpb25lcyBpbmRlcGVuZGllbnRlcyBwYXJhIGV2YWx1YXIgbGEgcm9idXN0ZXouIExvcyByZXN1bHRhZG9zIG11ZXN0cmFuIHF1ZSBlbCBHQSBwdWVkZSBlbmNvbnRyYXIgYXByb3hpbWFjaW9uZXMgYWwgbcOtbmltbyBnbG9iYWwgZW4gYW1ib3MgcHJvYmxlbWFzLCBhdW5xdWUgbGEgZnVuY2nDs24gUmFzdHJpZ2luIChtw7psdGlwbGVzIG3DrW5pbW9zIGxvY2FsZXMpIHByZXNlbnRhIG3DoXMgdmFyaWFiaWxpZGFkIHkgZGlmaWN1bHRhZCwgZXNwZWNpYWxtZW50ZSBlbiAzRC4gPGEgbmFtZT0iaW8xLjUuNy4iPjwvYT4gXCMgQ29uY2x1c2nDs24gR2VuZXJhbA0KDQpBbCB0ZXJtaW5hciBlc3RlIHRyYWJham8sIGxhIHZlcmRhZCBlcyBxdWUgdW5vIHNlIGRhIGN1ZW50YSBkZSBsbyBwb2Rlcm9zb3MgeSBmbGV4aWJsZXMgcXVlIHB1ZWRlbiBzZXIgbG9zIGFsZ29yaXRtb3MgYmlvaW5zcGlyYWRvcyBjdWFuZG8gc2UgdHJhdGEgZGUgcmVzb2x2ZXIgcHJvYmxlbWFzIGRlIG9wdGltaXphY2nDs24sIHRhbnRvIG51bcOpcmljb3MgY29tbyBjb21iaW5hdG9yaW9zLiBFbiBsYSBwcmltZXJhIHBhcnRlLCBleHBlcmltZW50YW1vcyBjb24gZnVuY2lvbmVzIGNsw6FzaWNhcyBjb21vIFJvc2VuYnJvY2sgeSBSYXN0cmlnaW4gdXNhbmRvIG3DqXRvZG9zIGNvbW8gZWwgZGVzY2Vuc28gZGUgZ3JhZGllbnRlLCBQU08geSBhbGdvcml0bW9zIGdlbsOpdGljb3MuIExvIGludGVyZXNhbnRlIGZ1ZSB2ZXIgY8OzbW8gbG9zIG3DqXRvZG9zIGJpb2luc3BpcmFkb3MsIGluc3BpcmFkb3MgZW4gbGEgbmF0dXJhbGV6YSB5IGVsIGNvbXBvcnRhbWllbnRvIGNvbGVjdGl2bywgbG9ncmFuIGVzY2FwYXIgZGUgbG9zIG3DrW5pbW9zIGxvY2FsZXMgeSBleHBsb3JhciBlbCBlc3BhY2lvIGRlIHNvbHVjaW9uZXMgZGUgdW5hIGZvcm1hIG11Y2hvIG3DoXMgY3JlYXRpdmEgeSByb2J1c3RhIHF1ZSBsb3MgbcOpdG9kb3MgdHJhZGljaW9uYWxlcy4gTm8gc29sbyBlcyBjdWVzdGnDs24gZGUgZW5jb250cmFyIGVsIG3DrW5pbW8sIHNpbm8gZGUgY8OzbW8gc2UgbGxlZ2EgYSDDqWw6IGxhIGRpdmVyc2lkYWQsIGxhIGNvbGFib3JhY2nDs24geSBsYSBhZGFwdGFjacOzbiBjb25zdGFudGUgaGFjZW4gbGEgZGlmZXJlbmNpYS4NCg0KUGVybyBsYSBjb3NhIG5vIHNlIHF1ZWTDsyBhaMOtLiBFbiBsYSBzZWd1bmRhIHBhcnRlLCBub3MgbWV0aW1vcyBkZSBsbGVubyBlbiBsYSBvcHRpbWl6YWNpw7NuIGNvbWJpbmF0b3JpYSwgZW5mcmVudMOhbmRvbm9zIGFsIGNsw6FzaWNvIHByb2JsZW1hIGRlbCB2aWFqYW50ZSB1c2FuZG8gY29sb25pYSBkZSBob3JtaWdhcy4gQXF1w60sIGxhIGluc3BpcmFjacOzbiBlbiBlbCBjb21wb3J0YW1pZW50byBkZSBsYXMgaG9ybWlnYXMgcGFyYSBlbmNvbnRyYXIgcnV0YXMgw7NwdGltYXMgZW4gbGEgbmF0dXJhbGV6YSBzZSB0cmFkdWpvIGVuIHVuIGFsZ29yaXRtbyBjYXBheiBkZSBlbmNvbnRyYXIgc29sdWNpb25lcyBlZmljaWVudGVzIGVuIHByb2JsZW1hcyBkb25kZSBsYSBjYW50aWRhZCBkZSBjb21iaW5hY2lvbmVzIHBvc2libGVzIGVzIGFicnVtYWRvcmEuIEVzIGltcHJlc2lvbmFudGUgdmVyIGPDs21vLCBhIHRyYXbDqXMgZGUgbGEgY29vcGVyYWNpw7NuIHkgbGEgY29tdW5pY2FjacOzbiBpbmRpcmVjdGEgKGNvbW8gbGFzIGZlcm9tb25hcyBlbiBlbCBjYXNvIGRlIGxhcyBob3JtaWdhcyksIGVsIHNpc3RlbWEgZW5jdWVudHJhIGNhbWlub3MgY2FkYSB2ZXogbWVqb3JlcywgaW5jbHVzbyBjdWFuZG8gZWwgZXNwYWNpbyBkZSBiw7pzcXVlZGEgZXMgZ2lnYW50ZXNjby4NCg0KRW4gcmVzdW1lbiwgZXN0ZSB0cmFiYWpvIG5vIHNvbG8gbm9zIHBlcm1pdGnDsyBjb21wYXJhciB5IGVudGVuZGVyIGRpZmVyZW50ZXMgYWxnb3JpdG1vcywgc2lubyBxdWUgdGFtYmnDqW4gbm9zIG1vc3Ryw7MgbGEgaW1wb3J0YW5jaWEgZGUgcGVuc2FyICJmdWVyYSBkZSBsYSBjYWphIiB5IGRlIGluc3BpcmFybm9zIGVuIGxhIG5hdHVyYWxlemEgcGFyYSByZXNvbHZlciBwcm9ibGVtYXMgY29tcGxlam9zLiBMb3MgYWxnb3JpdG1vcyBiaW9pbnNwaXJhZG9zIG5vIHNvbiB1bmEgcmVjZXRhIG3DoWdpY2EsIHBlcm8gc8OtIHVuYSBoZXJyYW1pZW50YSBwb2Rlcm9zYSB5IGFkYXB0YWJsZSwgY2FwYXogZGUgZW5mcmVudGFyIGRlc2Fmw61vcyB0YW50byBlbiBlbCBtdW5kbyBjb250aW51byBjb21vIGVuIGVsIGRpc2NyZXRvLiBBZGVtw6FzLCB0cmFiYWphciBjb24gZXN0b3MgbcOpdG9kb3MgZm9tZW50YSBsYSBjcmVhdGl2aWRhZCwgZWwgdHJhYmFqbyBlbiBlcXVpcG8geSB1bmEgdmlzacOzbiBpbnRlcmRpc2NpcGxpbmFyaWEgcXVlLCBzaW4gZHVkYSwgZXMgY2xhdmUgZW4gbGEgY2llbmNpYSB5IGxhIGluZ2VuaWVyw61hIGRlIGhveS4NCg0KPGEgbmFtZT0iaW8yLiI+PC9hPg0KDQojIFBhcnRlIDIuIE9wdGltaXphY2nDs24gY29tYmluYXRvcmlhDQoNCjxhIG5hbWU9ImlvMi4xLiI+PC9hPg0KDQojIyAyLjEgUGxhbnRlYW1pZW50byBkZWwgcHJvYmxlbWENCg0KRXN0ZSB0cmFiYWpvIHJlc3VlbHZlIGVsIHByb2JsZW1hIGRlbCB2aWFqZXJvIChUU1ApIHBhcmEgdW4gdmVuZGVkb3IgcXVlIGRlYmUgdmlzaXRhciAxMyBjaXVkYWRlcyBwcmluY2lwYWxlcyBkZSBDb2xvbWJpYSwgb3B0aW1pemFuZG8gbGEgcnV0YSBtZWRpYW50ZSBBbnQgQ29sb255IE9wdGltaXphdGlvbiAoQUNPKSB5IEFsZ29yaXRtb3MgR2Vuw6l0aWNvcyAoR0EpLiBMb3MgY29zdG9zIHRvdGFsZXMgc2UgY2FsY3VsYW4gY29uc2lkZXJhbmRvOiAtIFRpZW1wbyBkZWwgdmVuZGVkb3I6IENvc3RvcyBwb3IgaG9yYSBkZSBcJDMwLDAwMCwgXCQ1MCwwMDAgeSBcJDcwLDAwMCBDT1AsIGNvbiB1bmEgdmVsb2NpZGFkIHByb21lZGlvIGRlIDYwIGttL2guIC0gUGVhamVzOiBDb3N0b3MgZXhhY3RvcyBiYXNhZG9zIGVuIGRhdG9zIGRlIElOVklBUyB5IGNvbG9tYmlhcGVhamVzLmNvbSwgYWp1c3RhZG9zIGFsIDEwJSBkZSBpbmNyZW1lbnRvIHBhcmEgYWJyaWwgZGUgMjAyNS4gLSBDb21idXN0aWJsZTogVmVow61jdWxvIERGU0sgQzM1IGNvbiByZW5kaW1pZW50byBkZSAxMCBrbS9saXRybyB5IGdhc29saW5hIGEgXCQxNiwwMDAgQ09QL2dhbMOzbi4NCg0KTGEgc29sdWNpw7NuIMOzcHRpbWEgc2UgdmlzdWFsaXphIGNvbiB1biBHSUYgYW5pbWFkbyBxdWUgbXVlc3RyYSB1biBjYXJyaXRvIHJlY29ycmllbmRvIGxhcyBjYXJyZXRlcmFzIHByaW5jaXBhbGVzIGVudHJlIGxhcyBjaXVkYWRlcy4NCg0KYGBge3J9DQojIERlZmluaW1vcyBsYXMgMTMgY2l1ZGFkZXMgcHJpbmNpcGFsZXMgY29uIHN1cyBjb29yZGVuYWRhcyBnZW9ncsOhZmljYXMuDQpjaXVkYWRlcyA8LSBkYXRhLmZyYW1lKA0KICBDaXVkYWQgPSBjKCJCb2dvdMOhIiwgIk1lZGVsbMOtbiIsICJDYWxpIiwgIkJhcnJhbnF1aWxsYSIsICJDYXJ0YWdlbmEiLCAiQnVjYXJhbWFuZ2EiLCANCiAgICAgICAgICAgICAiUGVyZWlyYSIsICJDw7pjdXRhIiwgIkliYWd1w6kiLCAiTWFuaXphbGVzIiwgIlNhbnRhIE1hcnRhIiwgIlZpbGxhdmljZW5jaW8iLCAiUGFzdG8iKSwNCiAgTGF0aXR1ZCA9IGMoNC42MDk3LCA2LjI1MTgsIDMuNDM3MiwgMTAuOTY4NSwgMTAuMzk5NywgNy4xMjU0LCA0LjgxMzMsIDcuODkzOSwgDQogICAgICAgICAgICAgIDQuNDM4OSwgNS4wNjg5LCAxMS4yNDA4LCA0LjE0MjAsIDEuMjEzNiksDQogIExvbmdpdHVkID0gYygtNzQuMDgxNywgLTc1LjU2MzgsIC03Ni41MjI1LCAtNzQuNzgxMywgLTc1LjUxNDQsIC03My4xMTk4LCAtNzUuNjk2MSwgDQogICAgICAgICAgICAgICAtNzIuNTA3OCwgLTc1LjIzMjIsIC03NS41MTc0LCAtNzQuMTk5MCwgLTczLjYyNjYsIC03Ny4yODExKQ0KKQ0KI1VzYW1vcyB1bmEgbWF0cml6IGRlIGRpc3RhbmNpYXMgKGVuIGttKSBiYXNhZGEgZW4gcnV0YXMgcHJpbmNpcGFsZXMgcG9yIGNhcnJldGVyYS4NCmRpc3RhbmNpYXMgPC0gbWF0cml4KGMoDQogIDAsIDQyNiwgNDYwLCAxMDAyLCAxMDY4LCAzODQsIDMwNiwgNTUyLCAxNzQsIDI1NywgMTAwOCwgMTY1LCA4OTMsDQogIDQyNiwgMCwgNDE4LCA4NzYsIDk0MSwgNDYzLCAxNDIsIDYyOCwgMzI4LCAxNjYsIDg4NiwgNTk1LCA3NzQsDQogIDQ2MCwgNDE4LCAwLCAxMTM4LCAxMjAzLCA1OTUsIDI1OSwgNzYwLCAyOTYsIDM0MSwgMTE0NCwgNjI3LCA0MTYsDQogIDEwMDIsIDg3NiwgMTEzOCwgMCwgMTIyLCA2MTgsIDEwMTYsIDY2NCwgMTE3NiwgMTAxOSwgMTIyLCA4MzcsIDEzNjUsDQogIDEwNjgsIDk0MSwgMTIwMywgMTIyLCAwLCA2ODMsIDEwODEsIDcyOSwgMTI0MSwgMTA4NCwgMTg3LCA5MDIsIDE0MzAsDQogIDM4NCwgNDYzLCA1OTUsIDYxOCwgNjgzLCAwLCA0NTgsIDE2OCwgNTU4LCA0MDEsIDYyNCwgNDE5LCAxMDE3LA0KICAzMDYsIDE0MiwgMjU5LCAxMDE2LCAxMDgxLCA0NTgsIDAsIDYyMywgMzIzLCAyNCwgMTAyNiwgNTkwLCA3NjksDQogIDU1MiwgNjI4LCA3NjAsIDY2NCwgNzI5LCAxNjgsIDYyMywgMCwgNzI2LCA1NjYsIDY3MiwgNTg3LCAxMTg1LA0KICAxNzQsIDMyOCwgMjk2LCAxMTc2LCAxMjQxLCA1NTgsIDMyMywgNzI2LCAwLCAyNDcsIDExODIsIDMzOSwgNzI5LA0KICAyNTcsIDE2NiwgMzQxLCAxMDE5LCAxMDg0LCA0MDEsIDI0LCA1NjYsIDI0NywgMCwgMTAyOSwgNDMyLCA3MTIsDQogIDEwMDgsIDg4NiwgMTE0NCwgMTIyLCAxODcsIDYyNCwgMTAyNiwgNjcyLCAxMTgyLCAxMDI5LCAwLCA4NDMsIDEzNzEsDQogIDE2NSwgNTk1LCA2MjcsIDgzNywgOTAyLCA0MTksIDU5MCwgNTg3LCAzMzksIDQzMiwgODQzLCAwLCA4NTgsDQogIDg5MywgNzc0LCA0MTYsIDEzNjUsIDE0MzAsIDEwMTcsIDc2OSwgMTE4NSwgNzI5LCA3MTIsIDEzNzEsIDg1OCwgMA0KKSwgbnJvdz0xMywgYnlyb3c9VFJVRSkNCnJvd25hbWVzKGRpc3RhbmNpYXMpIDwtIGNvbG5hbWVzKGRpc3RhbmNpYXMpIDwtIGNpdWRhZGVzJENpdWRhZA0KYGBgDQoNCkVsIG9iamV0aXZvIGRlIGVzdGUgcHJvYmxlbWEgZXMgb3B0aW1pemFyIGNvbiByZXNwZWN0byBhIGxvcyBjb3N0b3MgeSBubyBhIGxhcyBkaXN0YW5jaWFzIGVudHJlIGNpdWRhZGVzLCBwb3IgbG8gcXVlIHNlIHRpZW5lbiBxdWUgY29uc2lkZXJhciBsb3MgY29zdG9zIGRlIGNvbWJ1c3RpYmxlLCBkZSBwZWFqZXMgeSBjdcOhbnRvIGNvYnJhIGVsIHZlbmRlZG9yIHBvciBob3JhIGRlIHRyYWJham8uIFNpbiBlbWJhcmdvLCBsYSBkaXN0YW5jaWEgYWZlY3RhcsOhIGFsIHZhbG9yIGRlIHRvZG9zIGVzdG9zIGNvc3RvcywgeSBwb3IgbG8gdGFudG8gaGF5IHF1ZSBjb25zaWRlcmFybGEuIEFkaWNpb25hbG1lbnRlLCB0b2RvcyBlc3RvcyBjb3N0b3MgZXN0w6FuIGVuIGZ1bmNpw7NuIGRlIGxhIGRpc3RhbmNpYSBlbiBtZXRyb3MsIHBvciBsbyBxdWUgZXMgbmVjZXNhcmlvIHJlYWxpemFyIGxhIGNvbnZlcnNpw7NuIGRlIGxhdGl0dWQtbG9uZ2l0dWQgYSBjb29yZGVuYWRhcyBlbiBtZXRyb3MuIFBhcmEgZXN0byBzZSB1c8OzIGxhIGxpYnJlcsOtYSAic2YiIHBhcmEgcmVhbGl6YXIgbGEgY29udmVyc2nDs24gYWwgc2lzdGVtYSBkZSBjb29yZGVuYWRhcyBwbGFuYXMgVVRNLCBlbCBjdWFsIHJlcHJlc2VudGEgbG9zIHB1bnRvcyBkZWwgZ2xvYm8gZW4gbWV0cm9zLg0KDQpMdWVnbywgc2UgY3JlYSBsYSBtYXRyaXogZGUgZGlzdGFuY2lhcyBlbiBtZXRyb3MgZW50cmUgY2FkYSBjaXVkYWQuDQoNCkFob3JhLCBoYXkgcXVlIGNvbnNpZGVyYXIgbG9zIGNvc3RvcyBwYXJhIHBvZGVyIGNyZWFyIHVuYSBtYXRyaXogZGUgY29zdG9zIHBhcmEgcmVzb2x2ZXIgZWwgcHJvYmxlbWEgZGUgb3B0aW1pemFjacOzbi4NCg0KQ29uIHJlc3BlY3RvIGFsIGNvc3RvIGRlbCBjb21idXN0aWJsZSwgZXN0ZSBkZXBlbmRlcsOhIGRlbCB2ZWjDrWN1bG8gcXVlIGVsIHZlbmRlZG9yIHV0aWxpemFyw6EgcGFyYSByZWFsaXphciBsYXMgZW50cmVnYXMuIFBhcmEgZXN0ZSBwcm9ibGVtYSwgc2UgdXRpbGl6YXLDoSB1biBmdXJnw7NuIERGU0sgQzM1LCBlbCBjdWFsIHRpZW5lIHVuIGNvbnN1bW8gZGUgY29tYnVzdGlibGUgZGUgNy42IGxpdHJvcyBhcHJveGltYWRvIHBvciBjYWRhIDEwMCBLbSBkZSByZWNvcnJpZG8sIHF1ZSBzZSBwdWVkZSB0cmFkdWNpciBlbiAwLjAwMDA3NiBsaXRyb3MgcG9yIGNhZGEgMSBtZXRybyAoREZTSywgcy5mLiwgRXNwZWNpZmljYWNpb25lcyBGdXJnb24gQzM1KS4gQWRpY2lvbmFsbWVudGUsIHNlIGNvbnNpZGVyYSBlbCBwcmVjaW8gcHJvbWVkaW8gZGUgbGEgZ2Fzb2xpbmEgZW4gQ29sb21iaWEgcXVlLCBzZWd1biAoTGEgUmVww7pibGljYSwgMjAyNSksIHRpZW5lIHVuIHZhbG9yIGRlIFwkMTUuODI3IHBlc29zIGNvbG9tYmlhbm9zIHBvciBnYWzDs24sIHF1ZSBzZSBwdWVkZSB0cmFkdWNpciBlbiBcJDQuMDIyIHBlc29zIGNvbG9tYmlhbm9zIHBvciBsaXRybyBhcHJveGltYWRhbWVudGUuDQoNCmBgYHtyfQ0KZ2FzdG9fbGl0cm9fcG9yX21ldHJvIDwtIDAuMDAwMDc2DQpwcmVjaW9fZ2Fzb2xpbmFfcG9yX2xpdHJvIDwtIDQuMDIyIA0KY29zdG9zX2NvbWJ1c3RpYmxlIDwtIGRpc3RhbmNpYXMgKiBnYXN0b19saXRyb19wb3JfbWV0cm8gKiBwcmVjaW9fZ2Fzb2xpbmFfcG9yX2xpdHJvDQpyb3duYW1lcyhjb3N0b3NfY29tYnVzdGlibGUpIDwtIG5vbWJyZV9jaXVkYWRlcw0KY29sbmFtZXMoY29zdG9zX2NvbWJ1c3RpYmxlKSA8LSBub21icmVfY2l1ZGFkZXMNCnByaW50KGNvc3Rvc19jb21idXN0aWJsZSkNCmBgYA0KDQpDb25zaWRlcmFuZG8gZWwgY29zdG8gZGUgbG9zIHBlYWplcywgc2UgdXNhcsOhbiBsb3MgZGF0b3MgZGUgKEludmlhcywgMjAyNCkgeSAoTWludHJhbnNwb3J0ZSwgMjAyNSkgcGFyYSBjYWxjdWxhciBlbCB2YWxvciBwcm9tZWRpbyBkZSBjYWRhIHBlYWplIGRlIGxhcyBjaXVkYWRlcyBjb25zaWRlcmFkYXMgeSBzZSBhc3VtaXLDoSBxdWUgZWwgdmVuZGVkb3IgcGFnYXLDoSBlbCB2YWxvciBwcm9tZWRpbyBkZWwgcGVhamUgZGUgbGEgY2l1ZGFkIGRlIG9yaWdlbiB5IGRlIGxhIGNpdWRhZCBkZSBkZXN0aW5vIGV4YWN0YW1lbnRlIDEgdmV6IGNhZGEgcXVlIGxhcyByZWNvcnJhLg0KDQpgYGB7cn0NCiNNYXRyaXogZGUgY29zdG9zIHRvdGFsZXMgZGUgcGVhamVzIChlbiBDT1ApLCBiYXNhZGEgZW4gZGF0b3MgcmVhbGVzIGFqdXN0YWRvcyBhbCB+MTAlIGRlIGluY3JlbWVudG8gcGFyYSBhYnJpbCBkZSAyMDI1Lg0KY29zdG9fcGVhamVzIDwtIG1hdHJpeChjKA0KICAwLCA2MDAwMCwgNjUwMDAsIDEwMDAwMCwgMTEwMDAwLCA2NTAwMCwgNDAwMDAsIDcwMDAwLCAyNTAwMCwgNDAwMDAsIDEwMDAwMCwgNDAwMDAsIDkwMDAwLCAgIyBCb2dvdMOhDQogIDYwMDAwLCAwLCA1NTAwMCwgOTAwMDAsIDEwMDAwMCwgNjUwMDAsIDMwMDAwLCA4MDAwMCwgNDAwMDAsIDMwMDAwLCA5MDAwMCwgODAwMDAsIDgwMDAwLCAgIyBNZWRlbGzDrW4NCiAgNjUwMDAsIDU1MDAwLCAwLCAxMzAwMDAsIDE0MDAwMCwgOTAwMDAsIDQwMDAwLCAxMDAwMDAsIDQwMDAwLCA1MDAwMCwgMTMwMDAwLCA4MDAwMCwgNTAwMDAsICAjIENhbGkNCiAgMTAwMDAwLCA5MDAwMCwgMTMwMDAwLCAwLCAyMTgwMCwgODAwMDAsIDEyMDAwMCwgOTAwMDAsIDE0MDAwMCwgMTIwMDAwLCAyMTgwMCwgOTAwMDAsIDE3MDAwMCwgICMgQmFycmFucXVpbGxhDQogIDExMDAwMCwgMTAwMDAwLCAxNDAwMDAsIDIxODAwLCAwLCA5MDAwMCwgMTMwMDAwLCAxMDAwMDAsIDE1MDAwMCwgMTMwMDAwLCA0MzYwMCwgMTAwMDAwLCAxODAwMDAsICAjIENhcnRhZ2VuYQ0KICA2NTAwMCwgNjUwMDAsIDkwMDAwLCA4MDAwMCwgOTAwMDAsIDAsIDgwMDAwLCAyNTAwMCwgODAwMDAsIDY1MDAwLCA4MDAwMCwgNTAwMDAsIDEzMDAwMCwgICMgQnVjYXJhbWFuZ2ENCiAgNDAwMDAsIDMwMDAwLCA0MDAwMCwgMTIwMDAwLCAxMzAwMDAsIDgwMDAwLCAwLCA5MDAwMCwgMjUwMDAsIDE1MDAwLCAxMjAwMDAsIDY1MDAwLCA4MDAwMCwgICMgUGVyZWlyYQ0KICA3MDAwMCwgODAwMDAsIDEwMDAwMCwgOTAwMDAsIDEwMDAwMCwgMjUwMDAsIDkwMDAwLCAwLCA5MDAwMCwgODAwMDAsIDkwMDAwLCA2NTAwMCwgMTQwMDAwLCAgIyBDw7pjdXRhDQogIDI1MDAwLCA0MDAwMCwgNDAwMDAsIDE0MDAwMCwgMTUwMDAwLCA4MDAwMCwgMjUwMDAsIDkwMDAwLCAwLCAyNTAwMCwgMTQwMDAwLCA0MDAwMCwgODAwMDAsICAjIEliYWd1w6kNCiAgNDAwMDAsIDMwMDAwLCA1MDAwMCwgMTIwMDAwLCAxMzAwMDAsIDY1MDAwLCAxNTAwMCwgODAwMDAsIDI1MDAwLCAwLCAxMjAwMDAsIDUwMDAwLCA2NTAwMCwgICMgTWFuaXphbGVzDQogIDEwMDAwMCwgOTAwMDAsIDEzMDAwMCwgMjE4MDAsIDQzNjAwLCA4MDAwMCwgMTIwMDAwLCA5MDAwMCwgMTQwMDAwLCAxMjAwMDAsIDAsIDkwMDAwLCAxNzAwMDAsICAjIFNhbnRhIE1hcnRhDQogIDQwMDAwLCA4MDAwMCwgODAwMDAsIDkwMDAwLCAxMDAwMDAsIDUwMDAwLCA2NTAwMCwgNjUwMDAsIDQwMDAwLCA1MDAwMCwgOTAwMDAsIDAsIDEyMDAwMCwgICMgVmlsbGF2aWNlbmNpbw0KICA5MDAwMCwgODAwMDAsIDUwMDAwLCAxNzAwMDAsIDE4MDAwMCwgMTMwMDAwLCA4MDAwMCwgMTQwMDAwLCA4MDAwMCwgNjUwMDAsIDE3MDAwMCwgMTIwMDAwLCAwICAgIyBQYXN0bw0KKSwgbnJvdz0xMywgYnlyb3c9VFJVRSkNCnJvd25hbWVzKGNvc3RvX3BlYWplcykgPC0gY29sbmFtZXMoY29zdG9fcGVhamVzKSA8LSBjaXVkYWRlcyRDaXVkYWQNCmBgYA0KDQpQb3Igw7psdGltbywgc2UgZGViZSBkZSBjb25zaWRlcmFyIGVsIHNhbGFyaW8gcG9yIGhvcmFzIHByb21lZGlvIGRlIHVuIHZlbmRlZG9yIHF1ZSBoYWdhIGRpY2hvcyByZWNvcnJpZG9zIHBhcmEgZW50cmVnYXIgbG9zIHBlZGlkb3MuIEFkaWNpb25hbCBhIHNlciB2ZW5kZWRvciwgZXN0YSBwZXJzb25hIHJlYWxpemFyw6EgbGFzIGVudHJlZ2FzIHkgbGEgY29uZHVjY2nDs24gZGUgbGEgbWVyY2FuY8OtYSwgcG9yIGxvIHF1ZSB0YW1iacOpbiBoYXkgcXVlIGNvbnNpZGVyYXIgc3UgcGFnbyBjb21vIHRyYW5zcG9ydGlzdGEuIERpY2hvIGVzdG8sIHNlIHByb21lZGlhcm9uIHNhbGFyaW9zIGRlIHVuIHRyYW5zcG9ydGlzdGEgeSB1biB2ZW5kZWRvciBwYXJhIHBvZGVyIGRldGVybWluYXIgZWwgc2FsYXJpbyBmaW5hbCBkZSBsYSBwZXJzb25hLiBTZWfDum4gKFRhbGVudC5jb20sIHMuZi4sICpTYWxhcmlvIG1lZGlvIHBhcmEgVHJhbnNwb3J0ZSBEZSBDYXJnYSBlbiBDb2xvbWJpYSAyMDI1KikgeSAoVGFsZW50LmNvbSwgcy5mLiwgKlNhbGFyaW8gbWVkaW8gcGFyYSBWZW5kZWRvciBlbiBDb2xvbWJpYSAyMDI1KiksIHVuIHRyYW5zcG9ydGlzdGEgZ2FuYSBlbiBwcm9tZWRpbyBcJDkuMzQxIHBlc29zIGNvbG9tYmlhbm9zIGxhIGhvcmEgeSB1biB2ZW5kZWRvciBoYWNlIFwkNy4xNDQgbGEgaG9yYTsgcG9yIGxvIHRhbnRvLCBlbCBzYWxhcmlvIGEgdXRpbGl6YXIgc2Vyw6EgZWwgXCQ4LjI0MiBwZXNvcyBsYSBob3JhLg0KDQpBc3VtaWVuZG8gcXVlIGVsIHZlbmRlZG9yIGNvbmR1Y2lyw6EgYSB1bmEgdmVsb2NpZGFkIG1lZGlhIGRlIDUwIGttL2ggYWwgZMOtYSwgcXVlIHNlIHBvZHLDrWFuIHRyYWR1Y2lyIGVuIDUwMDAwIG0vaCBwYXJhIGZhY2lsaXRhciBjw6FsY3Vsb3MsIHNlIHByb2NlZGUgYSBjYWxjdWxhciBlbCB0aWVtcG8gZGUgdmlhamUgeSwganVudG8gY29uIGVzdG8sIGN1w6FudG8gc2UgbGUgcGFnYXLDoSBhbCB2ZW5kZWRvciBwb3IgY2FkYSB2aWFqZS4NCg0KYGBge3J9DQp2ZWxvY2lkYWRfbWVkaWFfbWV0cm9zX3Bvcl9ob3JhIDwtIDUwMDAwDQpzYWxhcmlvX3ZlbmRlZG9yX2NvbG9tYmlhIDwtIDcxNDQNCnNhbGFyaW9fdHJhbnNwb3J0aXN0YV9jb2xvbWJpYSA8LSA5MzQxDQpzYWxhcmlvX2ZpbmFsIDwtIChzYWxhcmlvX3ZlbmRlZG9yX2NvbG9tYmlhICsgc2FsYXJpb190cmFuc3BvcnRpc3RhX2NvbG9tYmlhKS8yDQpjb3N0b3NfdmVuZGVkb3IgPC0gZGlzdGFuY2lhcyooMS92ZWxvY2lkYWRfbWVkaWFfbWV0cm9zX3Bvcl9ob3JhKSpzYWxhcmlvX2ZpbmFsDQpyb3duYW1lcyhjb3N0b3NfdmVuZGVkb3IpIDwtIG5vbWJyZV9jaXVkYWRlcw0KY29sbmFtZXMoY29zdG9zX3ZlbmRlZG9yKSA8LSBub21icmVfY2l1ZGFkZXMNCmNvc3Rvc192ZW5kZWRvcg0KDQpgYGANCg0KQ29uY2x1eWVuZG8sIGxhIG1hdHJpeiBkZSBjb3N0b3Mgc2ltcGxlbWVudGUgc2Vyw61hIGVsIHJlc3VsdGFkbyBkZSBsYSBzdW1hIGRlIGxhcyBhbnRlcmlvcmVzIG1hdHJpY2VzIHByZXZpYW1lbnRlIGRlZmluaWRhcywgeSBlc3RhIHNlcsOhIGxhIG1hdHJpeiBxdWUgc2UgdXRpbGl6YXLDoW4gZW4gbG9zIGRpc3RpbnRvcyBhbGdvcml0bW9zIHBhcmEgZW5jb250cmFyIGxhIG1lam9yIHJ1dGEuDQoNClNlIGNhbGN1bGFuIGxvcyBjb3N0b3MgdG90YWxlcyBjb25zaWRlcmFuZG8gLSBUaWVtcG8gOiBWZWxvY2lkYWQgcHJvbWVkaW8gZGUgNjAga20vaCwgLSBDb3N0b3MgcG9yIGhvcmEgXCQzMCwwMDAsXCQ1MCwwMDAsXCQ3MCwwMDAgQ09QLiAtIENvbWJ1c3RpYmxlOiBERlNLIEMzNSBjb24gMTBrbS9saXRybywgZ2Fzb2xpbmEgYSBcJDE2LDAwMCBDT1AvZ2Fsb24uDQoNCmBgYHtyfQ0KIyBDb3N0byBkZSBjb21idXN0aWJsZQ0KY29zdG9fY29tYnVzdGlibGVfa20gPC0gMTYwMDAgLyAoMTAgKiAzLjc4NSkgICMg4omIIDQyMi43MiBDT1Ava20NCiMgRnVlbnRlOiBQcmVjaW8gZXN0aW1hZG8gcGFyYSAyMDI1LCByZW5kaW1pZW50byBERlNLIEMzNSAoZXNwZWNpZmljYWNpb25lcyBkZWwgZmFicmljYW50ZSkNCg0KIyBGdW5jacOzbiBwYXJhIGNhbGN1bGFyIGNvc3Rvcw0KY2FsY3VsYXJfY29zdG9zIDwtIGZ1bmN0aW9uKGNvc3RvX2hvcmEpIHsNCiAgdGllbXBvcyA8LSBkaXN0YW5jaWFzIC8gNjAgICMgVGllbXBvIGVuIGhvcmFzDQogIGNvc3RvX3RpZW1wbyA8LSB0aWVtcG9zICogY29zdG9faG9yYQ0KICBjb3N0b19jb21idXN0aWJsZSA8LSBkaXN0YW5jaWFzICogY29zdG9fY29tYnVzdGlibGVfa20NCiAgY29zdG9fdG90YWwgPC0gY29zdG9fdGllbXBvICsgY29zdG9fY29tYnVzdGlibGUgKyBjb3N0b19wZWFqZXMNCiAgcmV0dXJuKGNvc3RvX3RvdGFsKQ0KfQ0KDQojIENhbGN1bGFyIG1hdHJpY2VzIGRlIGNvc3Rvcw0KY29zdG9faG9yYSA8LSBjKDMwMDAwLCA1MDAwMCwgNzAwMDApDQptYXRyaWNlc19jb3N0b3MgPC0gbGFwcGx5KGNvc3RvX2hvcmEsIGNhbGN1bGFyX2Nvc3RvcykNCmBgYA0KDQo8YSBuYW1lPSJpbzIuMi4iPjwvYT5cDQpcIyMgMi4yIEltcGxlbWVudGFjacOzbiBNw6l0b2RvIGRlIENvbG9uaWEgZGUgaG9ybWlnYXMgU2UgaW1wbGVtZW50YSBBbnQgQ29sb255IE9wdGltaXphY2lvbihBQ08pIHBhcmEgb3B0aW1pemFyIFRTUC5cDQpFc3RlIEFsZ29yaXRtbyAoQUNPKSBlc3RhIGluc3BpcmFkbyBlbiBlbCBjb21wb3J0YW1pZW50byBkZSBob3JtaWdhcyxlc3RlIGFsZ29yaXRtbyBzaW11bGEgY29tbyBsYXMgaG9ybWlnYXMgZW5jdWVudHJhbiBsYSBydXRhIG1hcyBjb3J0YSBkZWphbmRvIGZlcm9tb25hcy4gbGEgaWRlYSBlbiBzaSBlcyBxdWUgbGEgcnV0YSBtYXMgY29ydGEgYWN1bXVsYXJhIG1hcyBmZXJvbW9uYXMgY29uIGVsIHRpZW1wby4NCg0KYGBge3J9DQphY29fdHNwIDwtIGZ1bmN0aW9uKGNvc3RvX21hdHJpeiwgbl9hbnRzPTEwMCwgYWxwaGE9MSwgYmV0YT0yLCByaG89MC4xLCBtYXhfaXRlcj0yMDApIHsNCiAgbiA8LSBucm93KGNvc3RvX21hdHJpeikNCiAgcGhlcm9tb25lcyA8LSBtYXRyaXgoMSwgbnJvdz1uLCBuY29sPW4pDQogIGJlc3RfdG91ciA8LSBOVUxMICMgQWxtYWNlbmEgbGEgbWVqb3IgcnV0YSBlbmNvbnRyYWRhDQogIGJlc3RfY29zdCA8LSBJbmYgIyBBbG1hY2VuYSBlbCBjb3N0byBtw61uaW1vIGluaWNpYWwgKGluZmluaXRvKQ0KICBoaXN0b3J5IDwtIGxpc3QoKSAjIFJlZ2lzdHJhIGVsIHByb2dyZXNvIGRlIGxhcyBpdGVyYWNpb25lcw0KICANCiAgZm9yIChpdGVyIGluIDE6bWF4X2l0ZXIpIHsgICAgICAgICAgICAgICAgICAjIEJ1Y2xlIHByaW5jaXBhbCBwYXJhIGl0ZXJhY2lvbmVzIChtw6F4aW1vIDIwMCkNCiAgICB0b3VycyA8LSBtYXRyaXgoTkEsIG5yb3c9bl9hbnRzLCBuY29sPW4pICAjIE1hdHJpeiBwYXJhIGFsbWFjZW5hciBydXRhcyBkZSB0b2RhcyBsYXMgaG9ybWlnYXMNCiAgICBjb3N0cyA8LSBudW1lcmljKG5fYW50cykgICAgICAgICAgICAgICAgICAjIFZlY3RvciBwYXJhIGNvc3RvcyBkZSBjYWRhIGhvcm1pZ2ENCiAgICANCiAgICBmb3IgKGFudCBpbiAxOm5fYW50cykgeyAgICAgICAgICAgICAgICMgU2ltdWxhIGVsIG1vdmltaWVudG8gZGUgY2FkYSBob3JtaWdhICgxMDAgcG9yIGl0ZXJhY2nDs24pDQogICAgICBjdXJyZW50IDwtIHNhbXBsZSgxOm4sIDEpICAgICAgICAgICAjIENvbWllbnphIGVuIHVuYSBjaXVkYWQgYWxlYXRvcmlhDQogICAgICB0b3VyIDwtIGN1cnJlbnQgICAgICAgICAgICAgICAgICAgICAjIEluaWNpYWxpemEgbGEgcnV0YSBjb24gbGEgY2l1ZGFkIGFjdHVhbA0KICAgICAgdmlzaXRlZCA8LSByZXAoRkFMU0UsIG4pICAgICAgICAgICAgIyBNYXJjYSBjaXVkYWRlcyB2aXNpdGFkYXMNCiAgICAgIHZpc2l0ZWRbY3VycmVudF0gPC0gVFJVRQ0KICAgICAgDQogICAgICBmb3IgKGkgaW4gMToobi0xKSkgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENvbnN0cnV5ZSBsYSBydXRhIHZpc2l0YW5kbyB0b2RhcyBsYXMgY2l1ZGFkZXMNCiAgICAgICAgcHJvYnMgPC0gKHBoZXJvbW9uZXNbY3VycmVudCxdIF4gYWxwaGEpICogKCgxIC8gY29zdG9fbWF0cml6W2N1cnJlbnQsXSkgXiBiZXRhKQ0KICAgICAgICBwcm9ic1t2aXNpdGVkXSA8LSAwICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgIHByb2JzIDwtIHByb2JzIC8gc3VtKHByb2JzKQ0KICAgICAgICBuZXh0X2NpdHkgPC0gc2FtcGxlKDE6biwgMSwgcHJvYj1wcm9icykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTm9ybWFsaXphIHByb2JhYmlsaWRhZGVzDQogICAgICAgIHRvdXIgPC0gYyh0b3VyLCBuZXh0X2NpdHkpDQogICAgICAgIHZpc2l0ZWRbbmV4dF9jaXR5XSA8LSBUUlVFDQogICAgICAgIGN1cnJlbnQgPC0gbmV4dF9jaXR5DQogICAgICB9DQogICAgICANCiAgICAgICMgQXNpZ25hciB0b3VyIHNpbiBlbCByZXRvcm5vIChsb25naXR1ZCBuKQ0KICAgICAgdG91cnNbYW50LF0gPC0gdG91clsxOm5dICAjIFRvbWFtb3Mgc29sbyBsYXMgbiBjaXVkYWRlcw0KICAgICAgDQogICAgICAjIENhbGN1bGFyIGNvc3RvIGluY2x1eWVuZG8gZWwgcmV0b3JubyBhIGxhIGNpdWRhZCBpbmljaWFsDQogICAgICB0b3VyX3dpdGhfcmV0dXJuIDwtIGModG91ciwgdG91clsxXSkNCiAgICAgIGNvc3QgPC0gc3VtKGNvc3RvX21hdHJpeltjYmluZCh0b3VyX3dpdGhfcmV0dXJuWy1uLTFdLCB0b3VyX3dpdGhfcmV0dXJuWy0xXSldKQ0KICAgICAgY29zdHNbYW50XSA8LSBjb3N0DQogICAgICANCiAgICAgIGlmIChjb3N0IDwgYmVzdF9jb3N0KSB7DQogICAgICAgIGJlc3RfY29zdCA8LSBjb3N0DQogICAgICAgIGJlc3RfdG91ciA8LSB0b3VyX3dpdGhfcmV0dXJuDQogICAgICB9DQogICAgfQ0KICAgIA0KICAgICMgQWN0dWFsaXphciBmZXJvbW9uYXMNCiAgICBwaGVyb21vbmVzIDwtIHBoZXJvbW9uZXMgKiAoMSAtIHJobykNCiAgICBmb3IgKGFudCBpbiAxOm5fYW50cykgew0KICAgICAgdG91cl93aXRoX3JldHVybiA8LSBjKHRvdXJzW2FudCxdLCB0b3Vyc1thbnQsMV0pICAjIENlcnJhciBlbCBjaWNsbyBwYXJhIGZlcm9tb25hcw0KICAgICAgcGhlcm9tb25lc1tjYmluZCh0b3VyX3dpdGhfcmV0dXJuWy1uLTFdLCB0b3VyX3dpdGhfcmV0dXJuWy0xXSldIDwtIA0KICAgICAgICBwaGVyb21vbmVzW2NiaW5kKHRvdXJfd2l0aF9yZXR1cm5bLW4tMV0sIHRvdXJfd2l0aF9yZXR1cm5bLTFdKV0gKyAxIC8gY29zdHNbYW50XQ0KICAgIH0NCiAgICANCiAgICBoaXN0b3J5W1tpdGVyXV0gPC0gbGlzdCh0b3VyPWJlc3RfdG91ciwgY29zdD1iZXN0X2Nvc3QpDQogIH0NCiAgDQogIHJldHVybihsaXN0KGJlc3RfdG91cj1iZXN0X3RvdXIsIGJlc3RfY29zdD1iZXN0X2Nvc3QsIGhpc3Rvcnk9aGlzdG9yeSkpDQp9DQpgYGANCg0KPGEgbmFtZT0iaW8yLjMuIj48L2E+DQoNCiMjIDIuMyBJbXBsZW1lbnRhY2nDs24gTcOpdG9kbyBkZSBBbGdvcml0bW9zIEdlbsOpdGljb3MNCg0KU2UgdXRpbGl6YSBlbCBwYXF1ZXRlIGRlIEdBIHBhcmEgb3B0aW1pemFyIGVsIFRTUC4gQWPDoSBzZSB1c2EgZWwgQWxnb3JpdG1vIEdlbsOpdGljbyhHQSkgZXN0YSBpbnNwaXJhZG8gZW4gbGEgZXZvbHVjacOzbiB5IHNlbGVjY2nDs24gbmF0dXJhbC4gRXN0ZSBhbGdvcml0bW8gZXZvbHVjaW9uYSB1bmEgcG9ibGFjacOzbiBkZSBzb2x1Y2lvbmVzKHJ1dGFzKSBtZWRpYW50ZSBjcnV6YW1pZW50byB5IG11dGFjacOzbiBsYSAiYXB0aXR1ZCIgbWlkZSBxdWUgdGFuIGJ1ZW5hIGVzIHVuYSBydXRhIHkgbGFzIG1lam9yZXMgcnV0YXMgc2UgdmFuIGNvbWJpbmFuZG8gcGFyYSBtZWpvcmFyLg0KDQpgYGB7cn0NCiMgTsO6bWVybyBkZSBjaXVkYWRlcw0Kbl9jaXVkYWRlcyA8LSAxMw0KDQojIEZ1bmNpw7NuIHBhcmEgbm9ybWFsaXphciBsYSBtYXRyaXogZGUgY29zdG9zLCB5YSBxdWUgc2VhcmNoX3RvdXJfYW50cw0KIyBmdW5jaW9uYSBjb24gdmFsb3JlcyBub3JtYWxpemFkb3MuDQojIFNlIG9wdMOzIHBvciB1c2FyIG5vcm1hbGl6YWNpw7NuIHpzY29yZS4NCm5vcm1hbGl6ZV96c2NvcmUgPC0gZnVuY3Rpb24obSkgew0KICAobSAtIG1lYW4obSkpIC8gc2QobSkNCn0NCg0KIyBOb3JtYWxpemFjacOzbiBkZSBtYXRyaXogZGUgY29zdG9zDQptYXRyaXpfY29zdG9zX25vcm1hbGl6YWRhIDwtIG5vcm1hbGl6ZV96c2NvcmUobWF0cml6X2Nvc3RvcykNCg0KIyBFamVjdWNpw7NuIGRlbCBtw6l0b2RvIGRlIGNvbG9uaWEgZGUgaG9ybWlnYXMNCnJlY29ycmlkb19vcHRpbWl6YWRvIDwtIHNlYXJjaF90b3VyX2FudHMobWF0cml6X2Nvc3Rvc19ub3JtYWxpemFkYSwgbl9jaXVkYWRlcywgSyA9IDgwLCBOID0gNDAsIGxvZz1UUlVFKQ0KcHJpbnQoIk1FSk9SIFJFQ09SUklETzogIikNCnByaW50KHJlY29ycmlkb19vcHRpbWl6YWRvJHRvdXIpDQpgYGANCg0KQSBwYXJ0aXIgZGUgbG8gYW50ZXJpb3Igc2UgcHVkbyBjcmVhciBlbCBzaWd1aWVudGUgbWFwYSBkZSBydXRhcyBxdWUgbXVlc3RyYSBsYXMgbWVqb3JlcyBydXRhcyBjYWxjdWxhZGFzIHBvciBsb3MgYWxnb3JpdG1vcyBwcmV2aWFtZW50ZSBpbXBsZW1lbnRhZG9zLg0KDQo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQohW10odHNwX2NvbG9tYmlhX2NhcnJpdG9fZGZzay5naWYpDQoNCioqRmlndXJhIDEyLioqIEFuaW1hY2nDs24gZGUgbGEgbWVqb3IgcnV0YSBkZWwgdmVuZGVkb3INCg0KOjo6IHtzdHlsZT0iZm9udC13ZWlnaHQ6Ym9sZDsgbWFyZ2luLXRvcDo4cHg7IGZvbnQtc2l6ZToxLjA1ZW07In0NCioqQW5pbWFjacOzbiBkZSBsYSBtZWpvciBydXRhIGRlbCB2ZW5kZWRvcioqDQo6OjoNCjo6OjoNCg0KOjo6OiB7c3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsifQ0KIVsqKkZpZ3VyYSAxMy4qKiBDb21wYXJhY2nDs24gZGUgY29zdG9zIMOzcHRpbW9zOiBBQ08gdnMgR0FdKGltYWdlcy9Db21wYXJhY2lvbkNvc3Rvc09wdGltb3MucG5nKQ0KDQo6Ojoge3N0eWxlPSJmb250LXdlaWdodDpib2xkOyBtYXJnaW4tdG9wOjhweDsgZm9udC1zaXplOjEuMDVlbTsifQ0KKipDb21wYXJhY2nDs24gZGUgY29zdG9zIMOzcHRpbW9zOiBBQ08gdnMgR0EqKg0KOjo6DQo6Ojo6DQoNCjo6Ojo6IHtzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyJ9DQo6Ojoge3N0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7In0NCiFbKipGaWd1cmEgMTQuKiogQ29tcGFyYWNpw7NuIGRlIGNvc3RvcyDDs3B0aW1vczogQUNPIHZzIEdBXShpbWFnZXMvRGVzZ2xvc2VDb3N0b3MucG5nKQ0KOjo6DQoNCjo6OiB7c3R5bGU9ImZvbnQtd2VpZ2h0OmJvbGQ7IG1hcmdpbi10b3A6OHB4OyBmb250LXNpemU6MS4wNWVtOyJ9DQpEZXNnbG9zZSBkZSBjb3N0b3MNCjo6Og0KOjo6OjoNCg0KUG9yIMO6bHRpbW8sIGVuIGxhIEZpZ3VyYSAxMyB5IEZpZ3VyYSAxNCByZXNwZWN0aXZhbWVudGUgc2UgbXVlc3RyYW4gdGFudG8gbGEgY29tcGFyYWNpw7NuIGRlIGNvc3RvcyDDs3B0aW1vcyBwYXJhIGFtYm9zIG3DqXRvZG9zIHV0aWxpemFkb3MgY29tbyBlbCBkZXNnbG9zZSBkZSBsb3MgY29zdG9zIHBhcmEgbGEgbWVqb3IgcnV0YSwgZG9uZGUgZXZpZGVudGVtZW50ZSBzZSBwdWVkZSB2ZXIgcXVlIGFtYm9zIG3DqXRvZG9zIHRpZW5lbiB1biByZW5kaW1pZW50byBzaW1pbGFyIHkgcXVlIGVsIDYwJSBkZSBsb3MgY29zdG9zIHNlIHZhbiBlbiBlbCBwYWdvIGRlIGxvcyBwZWFqZXMuDQoNCjxhIG5hbWU9ImlvMi40LiI+PC9hPg0KDQojIyAyLjQgQ29uY2x1c2lvbmVzDQoNCkVsIHByb2JsZW1hIGRlbCB2aWFqZXJvIChUU1ApIHBhcmEgbGFzIDEzIGNpdWRhZGVzIHByaW5jaXBhbGVzIGRlIENvbG9tYmlhIHNlIHB1ZG8gcmVzb2x2ZXIgZGUgbWFuZXJhIHNhdGlzZmFjdG9yaWEgdXRpbGl6YW5kbyBBbnQgQ29sb255IE9wdGltaXphdGlvbihBQ08pIHkgQWxnb3JpdG1vcyBHZW7DqXRpY29zKEdBKS4gbG9zIHByaW5jaXBhbGVzIGhhbGxhemdvcyBzb246IC0gUnV0YXMgw7NwdGltYXM6IExhIG1lam9yIHJ1dGEgcGFyYSB1biBjb3N0byBwb3IgaG9yYSBkZSBcJDUwLDAwMCBmdWUgKHZlciBHSUYpLCBjb24gdW4gY29zdG8gdG90YWwgZGUgXCQ2LjA2Ni4zMjcgQ09QLkxvcyBwZWFqZXMgcmVwcmVzZW50YW4gYXByb3hpbWFkYW1lbnRlIGVsICg2MC4xJSlkZWwgY29zdG8gdG90YWwsIHNlZ3VpZG9zIHBvciBlbCBjb21idXN0aWJsZSAoOS41JSkgeSBlbCB0aWVtcG8gKDMwLjUlKSAtIERlc2VtcGXDsW8gZGUgbG9zIGFsZ29yaXRtb3M6IEFDTyBtb3N0csOzIHVuYSBjb252ZXJnZW5jaWEgbcOhcyByw6FwaWRhIGVuIGxhcyBwcmltZXJhcyA1MCBpdGVyYWNpb25lcywgbWllbnRyYXMgcXVlIEdBIGV4cGxvcsOzIHVuIGVzcGFjaW8gZGUgc29sdWNpb25lcyBtw6FzIGFtcGxpbywgc3VnaXJpZW5kbyBxdWUgR0EgZXMgbcOhcyByb2J1c3RvIHBhcmEgcHJvYmxlbWFzIGNvbXBsZWpvcy4gLSBJbXBhY3RvIGRlbCBjb3N0byBwb3IgaG9yYTogQXVtZW50YXIgZWwgY29zdG8gcG9yIGhvcmEgZGUgXCQzMCwwMDAgYSBcJDcwLDAwMCBpbmNyZW1lbnTDsyBlbCBjb3N0byB0b3RhbCBlbiBbdmVyIHRhYmxhXSUsIHBlcm8gZWwgb3JkZW4gZGUgbGFzIGNpdWRhZGVzIHBlcm1hbmVjacOzIGVzdGFibGUsIGluZGljYW5kbyBxdWUgbG9zIGNvc3RvcyBmaWpvcyAocGVhamVzIHkgY29tYnVzdGlibGUpIGRvbWluYW4uIC0gVmlzdWFsaXphY2nDs24gbWVqb3JhZGE6IExhIGFuaW1hY2nDs24gZGVsIGNhcnJpdG8gcmVjb3JyaWVuZG8gY2FycmV0ZXJhcyBwcmluY2lwYWxlcyBtZWpvcmEgbGEgaW50ZXJwcmV0YWNpw7NuIGRlIGxhIHJ1dGEgw7NwdGltYSwgbW9zdHJhbmRvIHVuIHJlY29ycmlkbyByZWFsaXN0YSBiYXNhZG8gZW4gZGF0b3MgZGUgT1NSTS4NCg0KTG9zIGFsZ29yaXRtb3MgYmlvaW5zcGlyYWRvcyBzb24gZWZlY3Rpdm9zLCBwZXJvIHJlcXVpZXJlbiBjYWxpYnJhY2nDs24uQWRlbWFzIGxhIHZpc3VhbGl6YWNpw7NuIGFuaW1hZGEgY29uIHJ1dGFzIHJlYWxlcyB5IHVuIGNhcnJpdG8gbWVqb3JhIGxhIGNvbXVuaWNhY2nDs24gZGUgcmVzdWx0YWRvcy4geSBwZXJtaXRlIGVudGVuZGVyIG1lam9yIGVsIG1vZGVsby4gTGEgcHJlY2lzacOzbiBkZSBsb3MgZGF0b3MgKGRpc3RhbmNpYXMsIHBlYWplcywgcnV0YXMpIGVzIGNyw610aWNhIHBhcmEgYXBsaWNhY2lvbmVzIGluZHVzdHJpYWxlcy4NCg0KPGEgbmFtZT0iaW81LiI+PC9hPg0KDQojIENvbmNsdXNpw7NuIEdlbmVyYWwNCg0KQWwgdGVybWluYXIgZXN0ZSB0cmFiYWpvLCBsYSB2ZXJkYWQgZXMgcXVlIHVubyBzZSBkYSBjdWVudGEgZGUgbG8gcG9kZXJvc29zIHkgZmxleGlibGVzIHF1ZSBwdWVkZW4gc2VyIGxvcyBhbGdvcml0bW9zIGJpb2luc3BpcmFkb3MgY3VhbmRvIHNlIHRyYXRhIGRlIHJlc29sdmVyIHByb2JsZW1hcyBkZSBvcHRpbWl6YWNpw7NuLCB0YW50byBudW3DqXJpY29zIGNvbW8gY29tYmluYXRvcmlvcy4gRW4gbGEgcHJpbWVyYSBwYXJ0ZSwgZXhwZXJpbWVudGFtb3MgY29uIGZ1bmNpb25lcyBjbMOhc2ljYXMgY29tbyBSb3NlbmJyb2NrIHkgUmFzdHJpZ2luIHVzYW5kbyBtw6l0b2RvcyBjb21vIGVsIGRlc2NlbnNvIGRlIGdyYWRpZW50ZSwgUFNPIHkgYWxnb3JpdG1vcyBnZW7DqXRpY29zLiBMbyBpbnRlcmVzYW50ZSBmdWUgdmVyIGPDs21vIGxvcyBtw6l0b2RvcyBiaW9pbnNwaXJhZG9zLCBpbnNwaXJhZG9zIGVuIGxhIG5hdHVyYWxlemEgeSBlbCBjb21wb3J0YW1pZW50byBjb2xlY3Rpdm8sIGxvZ3JhbiBlc2NhcGFyIGRlIGxvcyBtw61uaW1vcyBsb2NhbGVzIHkgZXhwbG9yYXIgZWwgZXNwYWNpbyBkZSBzb2x1Y2lvbmVzIGRlIHVuYSBmb3JtYSBtdWNobyBtw6FzIGNyZWF0aXZhIHkgcm9idXN0YSBxdWUgbG9zIG3DqXRvZG9zIHRyYWRpY2lvbmFsZXMuIE5vIHNvbG8gZXMgY3Vlc3Rpw7NuIGRlIGVuY29udHJhciBlbCBtw61uaW1vLCBzaW5vIGRlIGPDs21vIHNlIGxsZWdhIGEgw6lsOiBsYSBkaXZlcnNpZGFkLCBsYSBjb2xhYm9yYWNpw7NuIHkgbGEgYWRhcHRhY2nDs24gY29uc3RhbnRlIGhhY2VuIGxhIGRpZmVyZW5jaWEuDQoNClBlcm8gbGEgY29zYSBubyBzZSBxdWVkw7MgYWjDrS4gRW4gbGEgc2VndW5kYSBwYXJ0ZSwgbm9zIG1ldGltb3MgZGUgbGxlbm8gZW4gbGEgb3B0aW1pemFjacOzbiBjb21iaW5hdG9yaWEsIGVuZnJlbnTDoW5kb25vcyBhbCBjbMOhc2ljbyBwcm9ibGVtYSBkZWwgdmlhamFudGUgdXNhbmRvIGNvbG9uaWEgZGUgaG9ybWlnYXMuIEFxdcOtLCBsYSBpbnNwaXJhY2nDs24gZW4gZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIGhvcm1pZ2FzIHBhcmEgZW5jb250cmFyIHJ1dGFzIMOzcHRpbWFzIGVuIGxhIG5hdHVyYWxlemEgc2UgdHJhZHVqbyBlbiB1biBhbGdvcml0bW8gY2FwYXogZGUgZW5jb250cmFyIHNvbHVjaW9uZXMgZWZpY2llbnRlcyBlbiBwcm9ibGVtYXMgZG9uZGUgbGEgY2FudGlkYWQgZGUgY29tYmluYWNpb25lcyBwb3NpYmxlcyBlcyBhYnJ1bWFkb3JhLiBFcyBpbXByZXNpb25hbnRlIHZlciBjw7NtbywgYSB0cmF2w6lzIGRlIGxhIGNvb3BlcmFjacOzbiB5IGxhIGNvbXVuaWNhY2nDs24gaW5kaXJlY3RhIChjb21vIGxhcyBmZXJvbW9uYXMgZW4gZWwgY2FzbyBkZSBsYXMgaG9ybWlnYXMpLCBlbCBzaXN0ZW1hIGVuY3VlbnRyYSBjYW1pbm9zIGNhZGEgdmV6IG1lam9yZXMsIGluY2x1c28gY3VhbmRvIGVsIGVzcGFjaW8gZGUgYsO6c3F1ZWRhIGVzIGdpZ2FudGVzY28uDQoNCkVuIHJlc3VtZW4sIGVzdGUgdHJhYmFqbyBubyBzb2xvIG5vcyBwZXJtaXRpw7MgY29tcGFyYXIgeSBlbnRlbmRlciBkaWZlcmVudGVzIGFsZ29yaXRtb3MsIHNpbm8gcXVlIHRhbWJpw6luIG5vcyBtb3N0csOzIGxhIGltcG9ydGFuY2lhIGRlIHBlbnNhciAiZnVlcmEgZGUgbGEgY2FqYSIgeSBkZSBpbnNwaXJhcm5vcyBlbiBsYSBuYXR1cmFsZXphIHBhcmEgcmVzb2x2ZXIgcHJvYmxlbWFzIGNvbXBsZWpvcy4gTG9zIGFsZ29yaXRtb3MgYmlvaW5zcGlyYWRvcyBubyBzb24gdW5hIHJlY2V0YSBtw6FnaWNhLCBwZXJvIHPDrSB1bmEgaGVycmFtaWVudGEgcG9kZXJvc2EgeSBhZGFwdGFibGUsIGNhcGF6IGRlIGVuZnJlbnRhciBkZXNhZsOtb3MgdGFudG8gZW4gZWwgbXVuZG8gY29udGludW8gY29tbyBlbiBlbCBkaXNjcmV0by4gQWRlbcOhcywgdHJhYmFqYXIgY29uIGVzdG9zIG3DqXRvZG9zIGZvbWVudGEgbGEgY3JlYXRpdmlkYWQsIGVsIHRyYWJham8gZW4gZXF1aXBvIHkgdW5hIHZpc2nDs24gaW50ZXJkaXNjaXBsaW5hcmlhIHF1ZSwgc2luIGR1ZGEsIGVzIGNsYXZlIGVuIGxhIGNpZW5jaWEgeSBsYSBpbmdlbmllcsOtYSBkZSBob3kuDQoNCjxhIG5hbWU9Iml1My4iPjwvYT4NCg0KIyBSZXBvcnRlIGRlIGNvbnRyaWJ1Y2nDs24gaW5kaXZpZHVhbA0KDQojIyAtIExlb25hcmRvIEZlZGVyaWNvIENvcm9uYSBUb3JyZXMNCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24geSByZWFsaXphY2nDs24gZGUgaW1wbGVtZW50YWNpb25lcyBkZSBzZWNjacOzbiAiTcOpdG9kbyBkZSBhbGdvcml0bW9zIGV2b2x1dGl2b3MiLg0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIGdyYWZpY2FjacOzbiBlbiBQYXJ0ZSAyIGRlbCByZXBvcnRlLg0KDQotICAgQsO6c3F1ZWRhIGUgaW52ZXN0aWdhY2nDs24gZGUgZnVuY2lvbmVzIGRlIHBydWViYSBhIHV0aWxpemFyLg0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbiB5IHJlYWxpemFjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIHNlY2Npw7NuICJTZWxlY2Npw7NuIGUgaW1wbGVtZW50YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgZGUgcHJ1ZWJhIi4NCg0KIyMgLSBEYXZpZCBFc2NvYmFyIFJ1aXoNCg0KLSAgIERlZmluaWNpw7NuIHkgZXNjcml0dXJhIGRlIGVzdHJ1Y3R1cmEgZGVsIHJlcG9ydGUuDQoNCi0gICBBcG95byBlbiByZWRhY2Npw7NuIHkgcmVhbGl6YWNpw7NuIGRlIGltcGxlbWVudGFjaW9uZXMgZGUgc2VjY2nDs24gIlNlbGVjY2nDs24gZSBpbXBsZW1lbnRhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEiLg0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbnkgcmVhbGl6YWNpw7NuIGRlIGltcGxlbWVudGFjaW9uZXMgZGUgc2VjY2nDs24gIk3DqXRvZG8gZGUgb3B0aW1pemFjacOzbiBkZSBwYXJ0w61jdWxhcyIuDQoNCi0gICBBcG95byBlbiByZWRhY2Npw7NuIHkgcmVhbGl6YWNpw7NuIGRlIGltcGxlbWVudGFjaW9uZXMgZGUgbcOpdG9kb3MsIHBsYW50ZWFtaWVudG8geSBwcmVwcm9jZXNhbWllbnRvIGRlIGRhdG9zIFBhcnRlIDIgZGVsIHJlcG9ydGUuDQoNCiMjIC0gSm9oYW4gU2ViYXN0acOhbiBSb2JsZXMgUmluY8Ozbg0KDQotICAgSW1wbGVtZW50YWNpw7NuIHkgcHJ1ZWJhIGRlbCBtw6l0b2RvIGRlIGV2b2x1Y2nDs24gZGlmZXJlbmNpYWwgZW4gUiBwYXJhIGZ1bmNpb25lcyBkZSBSb3NlbmJyb2NrIHkgUmFzdHJpZ2luwqBlbsKgMkTCoHnCoDNELg0KDQotICAgQW7DoWxpc2lzIGRlIHJlc3VsdGFkb3MgbnVtw6lyaWNvcyB5IGdyw6FmaWNvcy4NCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24gZGUgc2VjY2nDs24gZGVsIGNvbnRlbmlkbyB0w6ljbmljbyByZWxhY2lvbmFkbyBjb24gZXN0ZSBtw6l0b2RvIGRlIGV2b2x1Y2lvbiBkaWZlcmVuY2lhbMKgZW7CoGVswqBpbmZvcm1lLg0KDQojIyAtIFNlYmFzdGlhbiBTb3RvIEFyY2lsYQ0KDQotICAgQXBveW8gZW4gcmVkYWNjacOzbiB5IHJlYWxpemFjacOzbiBkZSBpbXBsZW1lbnRhY2lvbmVzIGRlIHNlY2Npw7NuICJNw6l0b2RvIGRlIG9wdGltaXphY2nDs24gcG9yIGRlc2NlbnNvIGRlIGdyYWRpZW50ZSINCg0KLSAgIEFwb3lvIGVuIHJlZGFjY2nDs24gZGUgc2VjY2nDs24gIlNlbGVjY2nDs24gZSBpbXBsZW1lbnRhY2nDs24gZGUgbGFzIGZ1bmNpb25lcyBkZSBwcnVlYmEiLg0KDQo8YSBuYW1lPSJpdTQuIj48L2E+DQoNCiMgUmVwb3NpdG9yaW8gZGUgR2l0SHViIGRlbCBwcm95ZWN0bw0KDQpbaHR0cHM6Ly9naXRodWIuY29tL2RydWl6MzUvUk5BQkkyMDI1LTEtRXF1aXBvMy9dKGh0dHBzOi8vZ2l0aHViLmNvbS9kcnVpejM1L1JOQUJJMjAyNS0xLUVxdWlwbzMvdHJlZS9tYWluKXsudXJpfQ0KDQo8YSBuYW1lPSJpdTUuIj48L2E+DQoNCiMgQmlibGlvZ3JhZsOtYQ0KDQpBdXRvZmFjdC4gKDIwMjQpLiAqUGVhamVzIGVuIENvbG9tYmlhOiBDb25vY2Ugc3VzIHViaWNhY2lvbmVzIHkgcHJlY2lvcyAyMDI0LiogPGh0dHBzOi8vd3d3LmF1dG9mYWN0LmNvbS5jby9ibG9nL21pLWNhcnJvL3BlYWplcy9wZWFqZXMtY29sb21iaWEtcHJlY2lvcz4NCg0KREZTSy4gKHMuZi4pLiAqRXNwZWNpZmljYWNpb25lcyBGdXJnb24gQzM1LiogUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgPGh0dHA6Ly9zdGF0aWMubXVsdGlhdmlzby5jb20vdmVoaWNsZS9zcGVjcy8yMi1WUlpDNTY0WExCRTYtZGZzay1vdHJvcy1tb2RlbG9zLTIwMTctZnVyZ29uLWMzNS5wZGY+DQoNCklOVklBUy4gKHMuZi4pLiBTaXN0ZW1hIGRlIGluZm9ybWFjacOzbiB2aWFsLiA8aHR0cHM6Ly9oZXJtZXMuaW52aWFzLmdvdi5jby92aWFqZXJvc2VndXJvLz4NCg0KTGEgUmVww7pibGljYS4gKDIwMjUpLiAqUFJFQ0lPIERFIExBIEdBU09MSU5BLiogUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgPGh0dHBzOi8vd3d3LmxhcmVwdWJsaWNhLmNvL3ByZWNpby1kZS1sYS1nYXNvbGluYT4NCg0KTWludHJhbnNwb3J0ZS4gKDIwMjUpLiBDb2xvbWJpYXBlYWplcy4gPGh0dHBzOi8vY29sb21iaWFwZWFqZXMuY29tLz4NCg0KTW9sZ2EsIFNtdXRuaWNraS4gKDIwMDUpLiAqVGVzdCBmdW5jdGlvbnMgZm9yIG9wdGltaXphdGlvbiBuZWVkcy4qIDxodHRwczovL3JvYmVydG1hcmtzLm9yZy9DbGFzc2VzL0VOR1I1MzU4L1BhcGVycy9mdW5jdGlvbnMucGRmPg0KDQpUYWxlbnQuY29tLiAocy5mLikuICpTYWxhcmlvIG1lZGlvIHBhcmEgVHJhbnNwb3J0ZSBEZSBDYXJnYSBlbiBDb2xvbWJpYSAyMDI1Ki4gUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgPGh0dHBzOi8vY28udGFsZW50LmNvbS9zYWxhcnk/am9iPXRyYW5zcG9ydGUrZGUrY2FyZ2E+DQoNClRhbGVudC5jb20uIChzLmYuKS4gKlNhbGFyaW8gbWVkaW8gcGFyYSBWZW5kZWRvciBlbiBDb2xvbWJpYSAyMDI1Ki4gUmVjdXBlcmFkbyBlbCAyIGRlIG1heW8gZGUgMjAyNSwgZGUgPGh0dHBzOi8vY28udGFsZW50LmNvbS9zYWxhcnk/am9iPXZlbmRlZG9yPg0KDQpWaWFNaWNoZWxpbi4gKHMuZi4pLiBEaXN0YW5jaWFzIGVzdGltYWRhcyBjb24gVmlhTWljaGVsaW4uIDxodHRwczovL3d3dy52aWFtaWNoZWxpbi5jb20vPg0KDQpXaWtpcGVkaWEuIChzLmYuKS4gKlRlc3QgZnVuY3Rpb25zIGZvciBvcHRpbWl6YXRpb24qLiBXaWtpcGVkaWEuIFJlY3VwZXJhZG8gZWwgMiBkZSBtYXlvIGRlIDIwMjUsIGRlIDxodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9UZXN0X2Z1bmN0aW9uc19mb3Jfb3B0aW1pemF0aW9uPg0KDQpXaWtpcGVkaWEuIChzLmYuKS4gKlJvc2VuYnJvY2sgZnVuY3Rpb24qLiBXaWtpcGVkaWEuIFJlY3VwZXJhZG8gZWwgMiBkZSBtYXlvIGRlIDIwMjUsIGRlIFtodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Sb3NlbmJyb2NrXF9dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Jvc2VuYnJvY2tfZnVuY3Rpb24pey51cml9DQoNCldpa2lwZWRpYS4gKHMuZi4pLiAqUmFzdHJpZ2luIGZ1bmN0aW9uKi4gV2lraXBlZGlhLiBSZWN1cGVyYWRvIGVsIDIgZGUgbWF5byBkZSAyMDI1LCBkZSA8aHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmFzdHJpZ2luX2Z1bmN0aW9uPg0KDQpYLi1TLiBZYW5nLCBUZXN0IHByb2JsZW1zIGluIG9wdGltaXphdGlvbiwgaW46IEVuZ2luZWVyaW5nIE9wdGltaXphdGlvbjogQW4gSW50cm9kdWN0aW9uIHdpdGggTWV0YWhldXJpc3RpYyBBcHBsaWNhdGlvbnMgKEVkcyBYaW4tU2hlIFlhbmcpLCBKb2huIFdpbGV5ICYgU29ucywgKDIwMTApDQo=